package com.xh.bussiness.tiku.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.aspose.words.DocumentBuilder;
import com.aspose.words.ParagraphAlignment;
import com.github.pagehelper.StringUtil;
import com.xh.bussiness.tiku.bean.dto.AnswerResultDto;
import com.xh.bussiness.tiku.bean.dto.QuestionDto;
import com.xh.bussiness.tiku.bean.dto.QuestionImportPosDto;
import com.xh.bussiness.tiku.bean.dto.QuestionOptionDto;
import com.xh.bussiness.tiku.constant.PaperConstant;
import com.xh.bussiness.tiku.constant.PaperWidthConstant;
import com.xh.bussiness.tiku.constant.QuestionConstant;
import com.xh.bussiness.tiku.model.Question;
import com.xh.bussiness.tiku.service.IQuestionService;
import com.xh.bussiness.tiku.service.IQuestionTypeRelationService;
import com.xh.core.bean.SubStringBean;
import com.xh.core.exception.XhException;
import com.xh.core.util.HtmlUtils;
import com.xh.core.util.OfficeUtils;
import com.xh.core.util.RegexUtils;
import com.xh.core.util.StringUtils;
import com.xh.tools.question.constant.QuestionTypeEnum;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.scilab.forge.jlatexmath.TeXConstants;
import org.scilab.forge.jlatexmath.TeXFormula;
import org.scilab.forge.jlatexmath.TeXIcon;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import sun.misc.BASE64Encoder;

import javax.annotation.PostConstruct;
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.URL;
import java.util.*;
import java.util.List;
import java.util.regex.Matcher;

/*
 * @Author daiwei
 * @Description
 * @Date 2019/1/14 15:05
 **/
@Component
public class QuestionUtils {

    private static IQuestionService _questionService;

    private static IQuestionTypeRelationService _questionTypeRelationService;

    @Autowired
    private IQuestionService questionService;
    @Autowired
    private IQuestionTypeRelationService questionTypeRelationService;

    @PostConstruct
    public void init() {
        _questionService = questionService;
        _questionTypeRelationService = questionTypeRelationService;
    }

    private static String splitStr = ".,:;、。，：；．";

    private static String optionIndex = ".,:;、。，：；．";

    public static void main(String[] args) {
        String option = "A.<img src=\"\" width=\"13\" height=\"35\" alt=\"菁优网-jyeoo\" style=\"-aw-left-pos:0pt; -aw-rel-hpos:column; -aw-rel-vpos:paragraph; -aw-top-pos:0pt; -aw-wrap-type:inline\">x（x+1）=45 ";
        System.out.println(getHtmlWidth(option));
    }

    /**
     * latex 转 imgbase64
     *
     * @param latex 公式
     * @return
     */
    public static String latex2Png(String latex) {
        try {
            System.out.println("**********************");
            GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
            String[] fontNames = ge.getAvailableFontFamilyNames();
            for (String fontName : fontNames) {
                System.out.println(fontName);
            }
            System.out.println("**********************");
            TeXFormula formula = new TeXFormula(latex);
            // render the formla to an icon of the same size as the formula.
            TeXIcon icon = formula.createTeXIcon(TeXConstants.STYLE_DISPLAY, 23);
            // insert a border
            icon.setInsets(new Insets(0, 0, 0, 0));
            // now create an actual image of the rendered equation
            BufferedImage image = new BufferedImage(icon.getIconWidth(), icon.getIconHeight(), BufferedImage.TYPE_BYTE_GRAY);
            Graphics2D g2 = image.createGraphics();
            g2.setColor(Color.white);
            g2.fillRect(0, 0, icon.getIconWidth(), icon.getIconHeight());
            g2.setFont(new Font("宋体", Font.BOLD, 20));
            JLabel jl = new JLabel();
            jl.setForeground(new Color(0, 0, 0));
            icon.paintIcon(jl, g2, 0, 0);
            // at this point the image is created, you could also save it with ImageIO
            // saveImage(image, "png", "F:\\b.png");
            // ImageIO.write(image, "png", new File("F:\\c.png"));
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            try {
                ImageIO.write(image, "png", outputStream);
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
                return null;
            }
            byte[] buffer = outputStream.toByteArray();
            BASE64Encoder encoder = new BASE64Encoder();
            return ("data:image/png;base64," + encoder.encode(buffer));
        } catch (Exception e) {
            // e.printStackTrace();
            // ExceptionUtil.log(log, e);
            System.err.println("公式解析有误：\n" + latex);
            // e.printStackTrace();
            return null;
        }

    }

    /**
     * latex转MathML
     *
     * @param latex
     * @return
     */
    public static String latex2MathML(String latex) {
        String mathML = fmath.conversion.ConvertFromLatexToMathML.convertToMathML(latex);
        mathML = mathML.replaceFirst("<math ", "<math xmlns=\"http://www.w3.org/1998/Math/MathML\" ");
        return mathML;
    }

    /**
     * mathML转ooxml
     *
     * @param mathML
     * @return
     */
    public static String mathML2ooxml(String mathML) {
        return fmath.conversion.c.a.a(mathML);
    }


    /**
     * latex转ooxml
     *
     * @param latex
     * @return
     */
    public static String latex2ooxml(String latex) {
        return fmath.conversion.c.a.a(latex2MathML(latex));
    }

    /**
     * 将latex公式文本转化成图片html代码
     *
     * @param text
     */
    public static String convertLatexText2Html(String text) {
        if (StringUtils.isEmpty(text)) {
            return "";
        }
        text = HtmlUtils.recoverHtmlChar(text);
        //转换$$ …… $$形式公式，不能直接替换,比如有如下几种特殊情况：12123\$1123123$1$$$2$$2234$3$$4$23423
        //text=text.replaceAll("\\$\\$","\\$");
        int startIndex = text.indexOf('$');
        boolean isDouble = false;
        while (startIndex >= 0) {
            if (startIndex != 0 && '\\' == text.charAt(startIndex - 1)) {
                startIndex = text.indexOf('$', startIndex + 1);
                continue;
            }
            //判断起始节点是否是$$形态，如果是去掉一个并记录当前为$$状态
            if ('$' == text.charAt(startIndex + 1)) {
                isDouble = true;
                text = StringUtils.removeCharAt(text, startIndex);
            }
            int endIndex = text.indexOf('$', startIndex + 1);
            if (endIndex >= 0) {
                while ('\\' == text.charAt(endIndex - 1)) {
                    endIndex = text.indexOf('$', endIndex + 1);
                }
                if (endIndex < 0) {
                    break;
                }
                //判断结束节点是否是$$形态，如果是去掉一个并充值$$状态
                if (isDouble && '$' == text.charAt(endIndex + 1)) {
                    isDouble = false;
                    text = StringUtils.removeCharAt(text, endIndex);
                }
                startIndex = text.indexOf('$', endIndex + 1);
                continue;
            }
            break;
        }
        //转换\( …… \)形式公式
        text = text.replaceAll("\\\\\\(", "\\$");
        text = text.replaceAll("\\\\\\)", "\\$");
        text = text.replaceAll("\\\\\\[", "\\$");
        text = text.replaceAll("\\\\\\]", "\\$");

        StringBuffer result = new StringBuffer(text);
        List<SubStringBean> latexList = StringUtils.getLatexFromText(text);
        Collections.reverse(latexList);
        if (latexList.size() > 0) {
            for (SubStringBean latex : latexList) {
                String imgTag = "<img class=\"kfformula\" src=\"" + latex2Png(latex.getResult()) + "\" />";
                Document doc = Jsoup.parse(imgTag);
                Element imgEle = doc.getElementsByTag("img").get(0);
                imgEle.attr("data-latex", latex.getResult());
                imgTag = imgEle.outerHtml();
                result = result.replace(latex.getStart(), latex.getEnd() + 1, imgTag);
            }
        }
        return result.toString();
    }

    /**
     * html试题格式化解析
     *
     * @param html
     * @return
     */
    public static List<QuestionDto> analysisQuestionsFromHtml(String html) {
        html = convertAsposeToMSOffice(html);
        List<String> htmlLines = formatHtml(html);
        List<QuestionImportPosDto> resultPos = formatQuestionNew(htmlLines);

        List<QuestionDto> result = new ArrayList<>();
        for (QuestionImportPosDto item : resultPos) {
            QuestionDto tempResult = formatSingleQuestion(htmlLines, item.getQuestionType(), item.getStart(), item.getEnd());
            result.add(tempResult);
        }

        //result = formatQuestion(htmlLines);
        formatQuestionAfter(result);
        checkQuestionFormat(result);
        return result;
    }

    /**
     * 将Aspose处理的html转换为MsOffice的格式
     *
     * @param html
     * @return
     */
    private static String convertAsposeToMSOffice(String html) {
        String result = "";
        Document doc = Jsoup.parse(html);
        //将粗体、斜体、下划线、上下角标从样式转换为标签
        Elements eles = doc.select("span");
        for (Element ele : eles) {
            String style = ele.attr("style");
            if (style.indexOf("font-weight:bold") > 0) {
                ele.replaceWith(new Element("<b>" + ele.html() + "</b>"));
            } else if (style.indexOf("font-style:italic") > 0) {
                ele.replaceWith(new Element("<i>" + ele.html() + "</i>"));
            } else if (style.indexOf("text-decoration:underline") > 0) {
                ele.replaceWith(new Element("<u>" + ele.html() + "</u>"));
            } else if (style.indexOf("vertical-align:super") > 0) {
                ele.replaceWith(new Element("<sup>" + ele.html() + "</sup>"));
            } else if (style.indexOf("vertical-align:sub") > 0) {
                ele.replaceWith(new Element("<sub>" + ele.html() + "</sub>"));
            }
        }
        //去除批注
        eles = doc.select("a[href^=\"#_cmnt\"],div[id^=\"_cmnt\"]");
        for (Element ele : eles) {
            ele.remove();
        }
        result = doc.body().html();
        return result;
    }

    /**
     * 后置处理
     *
     * @param result
     */
    private static void formatQuestionAfter(List<QuestionDto> result) {
        for (QuestionDto question : result) {
            if (question.getBasicQuestionType().equals(QuestionConstant.TYPE.SINGLE)
                    || question.getBasicQuestionType().equals(QuestionConstant.TYPE.MUL)
                    || question.getBasicQuestionType().equals(QuestionConstant.TYPE.ORDER)
                    || question.getBasicQuestionType().equals(QuestionConstant.TYPE.MATCH)) {
                JSONArray options = new JSONArray();
                for (QuestionOptionDto option : question.getOptions()) {
                    JSONObject optionNew = new JSONObject();
                    optionNew.put("no", option.getNo());
                    optionNew.put("content", option.getContent());
                    options.add(optionNew);
                }
                question.setOption(options);
                if (question.getBasicQuestionType().equals(QuestionConstant.TYPE.MATCH)) {
                    question.setTitle(question.getTitle().replaceAll(QuestionConstant.REGEX_MATCH_RULE.BLANK_SELECT, "____"));
                }
            } else if (question.getBasicQuestionType().equals(QuestionConstant.TYPE.BLANK)) {
                //格式化填空，统一格式化成四个一组的下划线
                question.setTitle(question.getTitle().replaceAll(QuestionConstant.REGEX_MATCH_RULE.BLANK_SELECT, "____"));
            } else if (question.getBasicQuestionType().equals(QuestionConstant.TYPE.CLOZE)) {
                JSONArray clozeOptions = new JSONArray();
                for (QuestionOptionDto option : question.getOptions()) {
                    JSONArray options = new JSONArray();
                    for (QuestionOptionDto optionChild : option.getChilds()) {
                        JSONObject optionNew = new JSONObject();
                        optionNew.put("no", optionChild.getNo());
                        optionNew.put("content", optionChild.getContent());
                        options.add(optionNew);
                    }
                    clozeOptions.add(options);
                }
                question.setOption(clozeOptions);

                //格式化填空，统一格式化成四个一组的下划线
                question.setTitle(question.getTitle().replaceAll(QuestionConstant.REGEX_MATCH_RULE.CLOZE_BLANK_SELECT, "____"));
            } else if (question.getBasicQuestionType().equals(QuestionConstant.TYPE.LINK)) {
                JSONObject option = new JSONObject();
                JSONArray sources = new JSONArray();
                JSONArray targets = new JSONArray();
                for (QuestionOptionDto op : question.getOptions()) {
                    JSONObject optionNew = new JSONObject();
                    optionNew.put("no", op.getNo());
                    optionNew.put("content", op.getContent());
                    if (op.getType().equals("source")) {
                        sources.add(optionNew);
                    } else {
                        targets.add(optionNew);
                    }
                }
                option.put("source", sources);
                option.put("target", targets);
                question.setOption(option);
            }
        }
    }


    /**
     * 格式化html文档
     *
     * @param html
     * @return
     */
    private static List<String> formatHtml(String html) {
        //JXDocument doc = JXDocument.create(html);
        Document doc = Jsoup.parse(html);
        Elements paraList = doc.select("div > p,table");
        //获取word正文有效数据
        //List<Object> paraList = doc.sel("//div/(p|table)");
        System.out.println("段落总数：" + paraList.size());
        StringBuilder sb = new StringBuilder();
        for (Object o : paraList) {//HtmlAgilityPack.HtmlNode paraNode=paraList[3];
            if (o instanceof Element) {
                Element paraNode = (Element) o;
                //每个段落下的子标签拼接在一起，拼接式判断字标签是否包含图片，包含则取出图片，不包含则取出纯文本
                getChildNodeInfoNew(sb, paraNode);
                sb.append("\r\n");
            }

            //Debug.WriteLine("");
        }
        //sb=sb.replace("&nbsp", "");

        List<String> result = new ArrayList<>();

        String[] results = sb.toString().split("\r\n");
        for (String line : results) {
            if (!StringUtil.isEmpty(line.trim())) {
                line = line.replaceAll("&nbsp", "");
                result.add(line);
            }
        }
        return result;
    }

    /**
     * 递归格式化HTML节点
     *
     * @param sb
     * @param paraNode
     */
    private static void getChildNodeInfoNew(StringBuilder sb, Element paraNode) {
        if (paraNode.hasClass("MsoCommentReference")) {
            return;
        }
        if (paraNode.tagName().toLowerCase().equals("img")) {
            sb.append(paraNode.outerHtml().replaceAll("\r\n", ""));
            return;
        } else if (paraNode.tagName().toLowerCase().equals("u")) {
            if (paraNode.text().replaceAll("&nbsp;", "").replaceAll("_", "").replaceAll("　", "").trim().equals("")) {
                sb.append(paraNode.text().replaceAll("&nbsp;", "_").replaceAll("　", "__").replaceAll(" ", "_").replaceAll("\r\n", ""));
            } else {
                paraNode.html(paraNode.text());
                sb.append(paraNode.outerHtml().replaceAll("\r\n", ""));
            }
            return;
        } else if (paraNode.tagName().toLowerCase().equals("b")) {
            paraNode.html(paraNode.text());
            sb.append(paraNode.outerHtml().trim().replaceAll("\r\n", ""));
            return;
        } else if (paraNode.tagName().toLowerCase().equals("i")) {
            paraNode.html(paraNode.text());
            sb.append(paraNode.outerHtml().trim().replaceAll("\r\n", ""));
            return;
        } else if (paraNode.tagName().toLowerCase().equals("sub")) {
            paraNode.html(paraNode.text());
            sb.append(paraNode.outerHtml().trim().replaceAll("\r\n", ""));
            return;
        } else if (paraNode.tagName().toLowerCase().equals("sup")) {
            paraNode.html(paraNode.text());
            sb.append(paraNode.outerHtml().trim().replaceAll("\r\n", ""));
            return;
        } else if (paraNode.tagName().toLowerCase().equals("b")) {
            paraNode.html(paraNode.text());
            sb.append(paraNode.outerHtml().trim().replaceAll("\r\n", ""));
            return;
        } else if (paraNode.tagName().toLowerCase().equals("table")) {
            paraNode = formatTableElement(paraNode);
            sb.append(paraNode.outerHtml().trim().replaceAll("\r\n", ""));
            return;
        } else if (paraNode.tagName().toLowerCase().equals("br")) {
            sb.append("\r\n");
            return;
        } else if (paraNode.tagName().toLowerCase().equals("#text")) {
            String pcText = paraNode.text().replaceAll("&nbsp;", "").trim().replaceAll("\r\n", "");
            if (!StringUtils.isEmpty(pcText)) {
                sb.append(pcText);
            }
            return;
        } else if (paraNode.tagName().toLowerCase().equals("span")) {
            if (paraNode.children().size() == 0 && paraNode.childNodeSize() != 0) {
                sb.append(paraNode.text());
                return;
            }
        }

        if (paraNode.childNodeSize() > 0) {
            for (Element pcNode : paraNode.children()) {
                getChildNodeInfoNew(sb, pcNode);
            }
            return;
        }

    }

    /**
     * 简化表格标签
     *
     * @param paraNode
     * @return
     */
    private static Element formatTableElement(Element paraNode) {

        Elements elements = paraNode.select("td");
        for (Element tdNode : elements) {
            StringBuilder sb = new StringBuilder();
            //每个段落下的子标签拼接在一起，拼接式判断字标签是否包含图片，包含则取出图片，不包含则取出纯文本
            getChildNodeInfoNew(sb, tdNode);
            tdNode.html(sb.toString().replaceAll("　", "  ").trim());
        }
        return paraNode;
    }

    private static List<QuestionDto> formatQuestion(List<String> questionDatas) {
        return formatQuestion(questionDatas, 1, null, null);
    }

    /**
     * 格式化试题(多题，只支持基本题型)
     *
     * @param questionDatas
     * @return
     */
    private static List<QuestionDto> formatQuestion(List<String> questionDatas, Integer questionType, Integer start, Integer end) {
        if (start == null) {
            start = 0;
        }
        if (end == null) {
            end = questionDatas.size() - 1;
        }
        //1单选、2多选、3填空、4判断、5解答、6排序、7连线、8匹配、9阅读理解（英语）、10完形填空（英语）
        Integer defaultQuestionType = (questionType == null ? 1 : questionType);//默认题型
        int process = 0;//当前处理内容，0题型,1题干，2选项，3答案，4试题解析，5引导思考,6难度

        List<QuestionDto> result = new ArrayList<>();
        QuestionDto questionLast = null;
        for (int row = start; row <= end; row++) {
            //row++;
            String data = questionDatas.get(row);
            questionLast = result.size() > 0 ? result.get(result.size() - 1) : null;

            Integer defaultQuestionType_temp = changeDefaultQuestionType(data);
            if (defaultQuestionType_temp != null) {
                defaultQuestionType = defaultQuestionType_temp;
                process = 0;
                if (questionLast != null) {
                    questionLast.setEndRow(row - 1);
                }
                //判断是否是综合题
                /**
                 if (defaultQuestionType == 39 || defaultQuestionType == 40)
                 {
                 JObject questionNew=formatTogetherQuestion(questionDatas,row);
                 result.Add(questionNew);
                 row = int.Parse(questionNew["endRow"].ToString())+1;
                 }
                 */
                continue;
            }
            if (data.startsWith("【")) {
                process = 1;
                QuestionDto questionNew = new QuestionDto();
                questionNew.setTitle(data.indexOf("】") == data.length() - 1 ? "" : data.substring(data.indexOf("】") + 1));
                questionNew.setType(defaultQuestionType);
                questionNew.setStartRow(row);
                if (questionLast != null && questionLast.getEndRow() == null) {
                    questionLast.setEndRow(row - 1);
                }
                result.add(questionNew);
            } else {
                if (questionLast == null) {
                    continue;
                }
                List<QuestionOptionDto> options = questionLast.getOptions() == null ? new ArrayList<QuestionOptionDto>() : questionLast.getOptions();
                QuestionOptionDto lastOption = (options == null || options.size() == 0) ? null : options.get(options.size() - 1);

                //判断是否是答案
                if (RegexUtils.Match(data, QuestionConstant.REGEX_MATCH_RULE.RIGHT_ANSWER_TAG)) {
                    process = 3;
                    if (defaultQuestionType.equals(QuestionConstant.TYPE.SINGLE)) {
                        questionLast.setRightAnswer(getSingleRightAnswer(data, options));
                    } else if (defaultQuestionType.equals(QuestionConstant.TYPE.MUL)) {
                        questionLast.setRightAnswer(getMutlRightAnswer(data, options));
                    } else if (defaultQuestionType.equals(QuestionConstant.TYPE.BLANK)) {
                        //处理题干中的空
                        questionLast.setTitle(formatBlankQuestionSem(questionLast.getTitle()));
                        questionLast.setRightAnswer(getBlankRightAnswer(data));
                    } else if (defaultQuestionType.equals(QuestionConstant.TYPE.JUDGE)) {
                        questionLast.setRightAnswer(getJudgeRightAnswer(data));
                    } else if (defaultQuestionType.equals(QuestionConstant.TYPE.JIEDA)) {
                        questionLast.setRightAnswer(getJdRightAnswer(data));
                    } else if (defaultQuestionType.equals(QuestionConstant.TYPE.ORDER)) {
                        questionLast.setRightAnswer(getMutlRightAnswer(data, options));
                    } else if (defaultQuestionType.equals(QuestionConstant.TYPE.LINK)) {
                        questionLast.setRightAnswer(getLinkRightAnswer(data, options));
                    }

                    continue;
                }
                if (RegexUtils.Match(data, QuestionConstant.REGEX_MATCH_RULE.ANALYSIS_TAG)) {
                    process = 4;
                    questionLast.setAnalysis(getAnalysis(data));
                    continue;
                }
                if (RegexUtils.Match(data, QuestionConstant.REGEX_MATCH_RULE.EXAM_POINT_TAG)) {
                    process = 5;
                    questionLast.setExamPoint(getExamPoint(data));
                    continue;
                }
                if (RegexUtils.Match(data, QuestionConstant.REGEX_MATCH_RULE.DIFFICULT_TAG)) {
                    process = 6;
                    int dresult = getDifficulty(data);
                    if (dresult > 0) {
                        questionLast.setDifficult(dresult);
                    }
                    continue;
                }
                //判断是否是选项开始
                if (defaultQuestionType.equals(QuestionConstant.TYPE.SINGLE)
                        || defaultQuestionType.equals(QuestionConstant.TYPE.MUL)
                        || defaultQuestionType.equals(QuestionConstant.TYPE.ORDER)
                )//单选、多选、排序
                {
                    QuestionOptionDto option = checkIsOptions(data);
                    if (option != null && options.size() == 0 && (row < questionDatas.size() - 1)) {
                        //如果选项开始不是A，认为不是选项
                        if (!option.getName().equals("A")) {
                            continue;
                        }
                        //如果找到第一个选项后，下一行不再是选项，则认为不是选项
                        QuestionOptionDto optionNext = checkIsOptions(questionDatas.get(row + 1));
                        if (optionNext == null) {
                            continue;
                        }
                    }
                    if (option != null && process <= 2) {
                        process = 2;
                        option.setNo(options.size() + 1);
                        options.add(option);
                        if (lastOption == null) {
                            questionLast.setOptions(options);
                        }
                        continue;
                    }
                } else if (defaultQuestionType.equals(QuestionConstant.TYPE.BLANK))//填空
                {
                    //questionLast.setOptions(new ArrayList<>());
                } else if (defaultQuestionType.equals(QuestionConstant.TYPE.JIEDA))//解答
                {
                    //questionLast.setOptions(new ArrayList<>());
                } else if (defaultQuestionType.equals(QuestionConstant.TYPE.JUDGE))//判断
                {
                    //判断题忽略选项
                    QuestionOptionDto option = checkIsOptions(data);
                    if (option != null) {
                        continue;
                    }
                } else if (defaultQuestionType.equals(QuestionConstant.TYPE.LINK))//连线
                {
                    if (process == 1) {
                        options = checkIsTableOptions(data);
                        if (options != null) {
                            questionLast.setOptions(options);
                            continue;
                        }
                    }
                }

                //未匹配到规则时，认为是多行数据，拼接到上一个内容中
                if (!StringUtils.isEmpty(data.trim())) {
                    if (process == 1)//多行题干
                    {
                        questionLast.setTitle(questionLast.getTitle() + "<br/>" + data);
                    }

                    if (process == 2)//多行选项
                    {
                        //lastOption["content"] += "<br/>" + data;
                    }

                    if (process == 3)//多行答案
                    {
                        if (defaultQuestionType.equals(QuestionConstant.TYPE.JIEDA)) {
                            JSONObject lastRightAnswer = (JSONObject) questionLast.getRightAnswer();
                            if (!StringUtils.isEmpty(lastRightAnswer.getString("content"))) {
                                lastRightAnswer.replace("content", lastRightAnswer.getString("content") + "<br/>" + data);
                                questionLast.setRightAnswer(lastRightAnswer);
                            } else {
                                lastRightAnswer.replace("content", data);
                                questionLast.setRightAnswer(lastRightAnswer);
                            }
                        }
                        //questionLast["answer"]["content"] += "<br/>" + data;
                    }
                    if (process == 4)//试题解析
                    {
                        questionLast.setAnalysis(questionLast.getAnalysis() + "<br/>" + data);
                    }
                    if (process == 5)//考点分析
                    {
                        questionLast.setExamPoint(questionLast.getExamPoint() + "<br/>" + data);
                    }
                }
            }
        }
        if (questionLast != null) {
            questionLast.setEndRow(questionDatas.size() - 1);
        }


        return result;
    }

    /**
     * 格式化试题(单题，支持所有题型)
     *
     * @param questionDatas
     * @return
     */
    private static QuestionDto formatSingleQuestion(List<String> questionDatas, Integer questionType, Integer start, Integer end) {
        if (start == null) {
            start = 0;
        }
        if (end == null) {
            end = questionDatas.size() - 1;
        }
        //1单选、2多选、3填空、4判断、5解答、6排序、7连线、8匹配、9阅读理解（英语）、10完形填空（英语）
        Integer defaultQuestionType = (questionType == null ? 1 : questionType);//默认题型
//        if(defaultQuestionType.equals(QuestionConstant.TYPE.CLOZE)){
//            return formatQuestionCloze(questionDatas,start,end);
//        }
        int process = 0;//当前处理内容，0题型,1题干，2选项，3答案，4试题解析，5引导思考,6难度

        List<QuestionDto> result = new ArrayList<>();
        QuestionDto questionLast = null;
        for (int row = start; row <= end; row++) {
            //row++;
            String data = questionDatas.get(row);
            questionLast = result.size() > 0 ? result.get(result.size() - 1) : null;

            Integer defaultQuestionType_temp = changeDefaultQuestionType(data);
            if (defaultQuestionType_temp != null) {
                defaultQuestionType = defaultQuestionType_temp;
                process = 0;
                if (questionLast != null) {
                    questionLast.setEndRow(row - 1);
                }
                //判断是否是综合题
                /**
                 if (defaultQuestionType == 39 || defaultQuestionType == 40)
                 {
                 JObject questionNew=formatTogetherQuestion(questionDatas,row);
                 result.Add(questionNew);
                 row = int.Parse(questionNew["endRow"].ToString())+1;
                 }
                 */
                continue;
            }
            if (data.startsWith("【")) {
                process = 1;
                if (questionLast != null && questionLast.getEndRow() == null) {
                    questionLast.setEndRow(row - 1);
                    break;
                }
                QuestionDto questionNew = new QuestionDto();
                questionNew.setTitle(data.indexOf("】") == data.length() - 1 ? "" : data.substring(data.indexOf("】") + 1));
                questionNew.setType(defaultQuestionType);
                questionNew.setStartRow(row);
                result.add(questionNew);
            } else {
                if (questionLast == null) {
                    continue;
                }
                List<QuestionOptionDto> options = questionLast.getOptions() == null ? new ArrayList<QuestionOptionDto>() : questionLast.getOptions();
                QuestionOptionDto lastOption = (options == null || options.size() == 0) ? null : options.get(options.size() - 1);

                //判断是否是答案
                if (RegexUtils.Match(data, QuestionConstant.REGEX_MATCH_RULE.RIGHT_ANSWER_TAG)) {
                    process = 3;
                    if (defaultQuestionType.equals(QuestionConstant.TYPE.SINGLE)) {
                        questionLast.setRightAnswer(getSingleRightAnswer(data, options));
                    } else if (defaultQuestionType.equals(QuestionConstant.TYPE.MUL)) {
                        questionLast.setRightAnswer(getMutlRightAnswer(data, options));
                    } else if (defaultQuestionType.equals(QuestionConstant.TYPE.BLANK)) {
                        //处理题干中的空
                        questionLast.setTitle(formatBlankQuestionSem(questionLast.getTitle()));
                        questionLast.setRightAnswer(getBlankRightAnswer(data));
                    } else if (defaultQuestionType.equals(QuestionConstant.TYPE.JUDGE)) {
                        questionLast.setRightAnswer(getJudgeRightAnswer(data));
                    } else if (defaultQuestionType.equals(QuestionConstant.TYPE.JIEDA)) {
                        questionLast.setRightAnswer(getJdRightAnswer(data));
                    } else if (defaultQuestionType.equals(QuestionConstant.TYPE.ORDER)) {
                        questionLast.setRightAnswer(getMutlRightAnswer(data, options));
                    } else if (defaultQuestionType.equals(QuestionConstant.TYPE.LINK)) {
                        questionLast.setRightAnswer(getLinkRightAnswer(data, options));
                    } else if (defaultQuestionType.equals(QuestionConstant.TYPE.MATCH)) {
                        questionLast.setRightAnswer(getMutlRightAnswer(data, options));
                    } else if (defaultQuestionType.equals(QuestionConstant.TYPE.CLOZE)) {
                        questionLast.setRightAnswer(getClozeRightAnswer(data, options));
                    }

                    continue;
                }
                if (RegexUtils.Match(data, QuestionConstant.REGEX_MATCH_RULE.ANALYSIS_TAG)) {
                    process = 4;
                    questionLast.setAnalysis(getAnalysis(data));
                    continue;
                }
                if (RegexUtils.Match(data, QuestionConstant.REGEX_MATCH_RULE.EXAM_POINT_TAG)) {
                    process = 5;
                    questionLast.setExamPoint(getExamPoint(data));
                    continue;
                }
                if (RegexUtils.Match(data, QuestionConstant.REGEX_MATCH_RULE.DIFFICULT_TAG)) {
                    process = 6;
                    int dresult = getDifficulty(data);
                    if (dresult > 0) {
                        questionLast.setDifficult(dresult);
                    }
                    continue;
                }
                //判断是否是选项开始
                if (defaultQuestionType.equals(QuestionConstant.TYPE.SINGLE)
                        || defaultQuestionType.equals(QuestionConstant.TYPE.MUL)
                        || defaultQuestionType.equals(QuestionConstant.TYPE.ORDER)
                        || defaultQuestionType.equals(QuestionConstant.TYPE.MATCH)
                )//单选、多选、排序
                {
                    QuestionOptionDto option = checkIsOptions(data);
                    if (option != null && options.size() == 0 && (row < questionDatas.size() - 1)) {
                        //如果选项开始不是A，认为不是选项
                        if (!option.getName().equals("A")) {
                            continue;
                        }
                        //如果找到第一个选项后，下一行不再是选项，则认为不是选项
                        QuestionOptionDto optionNext = checkIsOptions(questionDatas.get(row + 1));
                        if (optionNext == null) {
                            continue;
                        }
                    }
                    if (option != null && process <= 2) {
                        process = 2;
                        option.setNo(options.size() + 1);
                        options.add(option);
                        if (lastOption == null) {
                            questionLast.setOptions(options);
                        }
                        continue;
                    }
                } else if (defaultQuestionType.equals(QuestionConstant.TYPE.BLANK))//填空
                {
                    //questionLast.setOptions(new ArrayList<>());
                } else if (defaultQuestionType.equals(QuestionConstant.TYPE.JIEDA))//解答
                {
                    //questionLast.setOptions(new ArrayList<>());
                } else if (defaultQuestionType.equals(QuestionConstant.TYPE.JUDGE))//判断
                {
                    //判断题忽略选项
                    QuestionOptionDto option = checkIsOptions(data);
                    if (option != null) {
                        continue;
                    }
                } else if (defaultQuestionType.equals(QuestionConstant.TYPE.LINK))//连线
                {
                    if (process == 1) {
                        options = checkIsTableOptions(data);
                        if (options != null) {
                            questionLast.setOptions(options);
                            continue;
                        }
                    }
                } else if (defaultQuestionType.equals(QuestionConstant.TYPE.CLOZE))//完形填空
                {
                    QuestionOptionDto clozeOption = checkIsClozeOptions(data);
                    if (clozeOption != null && options.size() == 0 && (row < questionDatas.size() - 1)) {
                        //如果选项开始不是1，认为不是选项
                        if (!clozeOption.getName().equals("1")) {
                            continue;
                        }
                        //如果找到第一个选项后，下一行不再是选项，则认为不是选项
                        QuestionOptionDto clozeOptionNext = checkIsClozeOptions(questionDatas.get(row + 1));
                        if (clozeOptionNext == null) {
                            continue;
                        }
                    }
                    if (clozeOption != null && process <= 2) {
                        process = 2;
                        clozeOption.setNo(options.size() + 1);
                        options.add(clozeOption);
                        if (lastOption == null) {
                            questionLast.setOptions(options);
                        }
                        continue;
                    }

                }

                //未匹配到规则时，认为是多行数据，拼接到上一个内容中
                if (!StringUtils.isEmpty(data.trim())) {
                    if (process == 1)//多行题干
                    {
                        questionLast.setTitle(questionLast.getTitle() + "<br/>" + data);
                    }

                    if (process == 2)//多行选项
                    {
                        //lastOption["content"] += "<br/>" + data;
                    }

                    if (process == 3)//多行答案
                    {
                        if (defaultQuestionType.equals(QuestionConstant.TYPE.JIEDA)) {
                            JSONObject lastRightAnswer = (JSONObject) questionLast.getRightAnswer();
                            if (!StringUtils.isEmpty(lastRightAnswer.getString("content"))) {
                                lastRightAnswer.replace("content", lastRightAnswer.getString("content") + "<br/>" + data);
                                questionLast.setRightAnswer(lastRightAnswer);
                            } else {
                                lastRightAnswer.replace("content", data);
                                questionLast.setRightAnswer(lastRightAnswer);
                            }
                        }
                        //questionLast["answer"]["content"] += "<br/>" + data;
                    }
                    if (process == 4)//试题解析
                    {
                        questionLast.setAnalysis(questionLast.getAnalysis() + "<br/>" + data);
                    }
                    if (process == 5)//考点分析
                    {
                        questionLast.setExamPoint(questionLast.getExamPoint() + "<br/>" + data);
                    }
                }
            }
        }
        if (questionLast != null) {
            questionLast.setEndRow(questionDatas.size() - 1);
        }


        return result.size() == 0 ? null : result.get(0);
    }


    private static QuestionDto formatQuestionReading(List<String> questionDatas, Integer start, Integer end) {
        Integer questionType = QuestionConstant.TYPE.READING;
        return null;
    }

    private static QuestionDto formatQuestionCloze(List<String> questionDatas, Integer start, Integer end) {
        Integer questionType = QuestionConstant.TYPE.CLOZE;
        return null;
    }

    /**
     * 新的试题格式化，修改为先确定完整试题位置，再进行解析
     *
     * @param questionDatas
     * @return
     */
    private static List<QuestionImportPosDto> formatQuestionNew(List<String> questionDatas) {
        int defaultQuestionType = 1;//默认题型
        List<QuestionImportPosDto> questionImportPosDtos = new ArrayList<>();

        for (int row = 0; row < questionDatas.size(); row++) {

            String data = questionDatas.get(row);
            Integer defaultQuestionType_temp = changeDefaultQuestionType(data);
            if (defaultQuestionType_temp != null) {
                if (questionImportPosDtos.size() > 0) {
                    QuestionImportPosDto questionImportPosDtoLast = questionImportPosDtos.get(questionImportPosDtos.size() - 1);
                    if (questionImportPosDtoLast.getEnd() == null) {
                        questionImportPosDtoLast.setEnd(row - 1);
                    }
                }
                defaultQuestionType = defaultQuestionType_temp;
                continue;
            }
            if (data.startsWith("【")) {
                if (questionImportPosDtos.size() > 0) {
                    QuestionImportPosDto questionImportPosDtoLast = questionImportPosDtos.get(questionImportPosDtos.size() - 1);
                    if (questionImportPosDtoLast.getEnd() == null) {
                        questionImportPosDtoLast.setEnd(row - 1);
                    }
                }
                QuestionImportPosDto questionImportPosDto = new QuestionImportPosDto();
                questionImportPosDto.setQuestionType(defaultQuestionType);
                questionImportPosDto.setStart(row);
                questionImportPosDtos.add(questionImportPosDto);
                continue;
            }
        }
        if (questionImportPosDtos.size() > 0) {
            QuestionImportPosDto questionImportPosDtoLast = questionImportPosDtos.get(questionImportPosDtos.size() - 1);
            if (questionImportPosDtoLast.getEnd() == null) {
                questionImportPosDtoLast.setEnd(questionDatas.size() - 1);
            }
        }
        return questionImportPosDtos;
    }


    /**
     * 改变当前默认试题类型
     *
     * @param data
     * @return
     */
    private static Integer changeDefaultQuestionType(String data) {
        if (RegexUtils.Match(data, QuestionConstant.REGEX_MATCH_RULE.SINGLE_TAG)) {
            return QuestionConstant.TYPE.SINGLE;
        } else if (RegexUtils.Match(data, QuestionConstant.REGEX_MATCH_RULE.MUL_TAG)) {
            return QuestionConstant.TYPE.MUL;
        } else if (RegexUtils.Match(data, QuestionConstant.REGEX_MATCH_RULE.BLANK_TAG)) {
            return QuestionConstant.TYPE.BLANK;
        } else if (RegexUtils.Match(data, QuestionConstant.REGEX_MATCH_RULE.JUDGE_TAG)) {
            return QuestionConstant.TYPE.JUDGE;
        } else if (RegexUtils.Match(data, QuestionConstant.REGEX_MATCH_RULE.JIEDA_TAG)) {
            return QuestionConstant.TYPE.JIEDA;
        } else if (RegexUtils.Match(data, QuestionConstant.REGEX_MATCH_RULE.ORDER_TAG)) {
            return QuestionConstant.TYPE.ORDER;
        } else if (RegexUtils.Match(data, QuestionConstant.REGEX_MATCH_RULE.LINK_TAG)) {
            return QuestionConstant.TYPE.LINK;
        } else if (RegexUtils.Match(data, QuestionConstant.REGEX_MATCH_RULE.MATCH_TAG)) {
            return QuestionConstant.TYPE.MATCH;
        } else if (RegexUtils.Match(data, QuestionConstant.REGEX_MATCH_RULE.CLOZE_TAG)) {
            return QuestionConstant.TYPE.CLOZE;
        }

        /**
         else if (Regex.Match(data, @"^(完形填空)").Success)
         {
         defaultQuestionType = 39;
         flag = true;
         }
         else if (Regex.Match(data, @"^(阅读理解)").Success)
         {
         defaultQuestionType = 40;
         flag = true;
         }
         */
        return null;
    }

    /**
     * 获取试题类型中文
     *
     * @param type
     * @return
     */
    public static String getQuestionTypeChinese(Integer type) {
        if (type.equals(QuestionConstant.TYPE.SINGLE)) {
            return "单选题";
        } else if (type.equals(QuestionConstant.TYPE.MUL)) {
            return "多选题";
        } else if (type.equals(QuestionConstant.TYPE.BLANK)) {
            return "填空题";
        } else if (type.equals(QuestionConstant.TYPE.JUDGE)) {
            return "判断题";
        } else if (type.equals(QuestionConstant.TYPE.JIEDA)) {
            return "解答题";
        } else if (type.equals(QuestionConstant.TYPE.ORDER)) {
            return "排序题";
        } else if (type.equals(QuestionConstant.TYPE.LINK)) {
            return "连线题";
        } else if (type.equals(QuestionConstant.TYPE.MATCH)) {
            return "匹配题";
        } else if (type.equals(QuestionConstant.TYPE.CLOZE)) {
            return "完型填空";
        } else if (type.equals(QuestionConstant.TYPE.COMB)) {
            return "综合题";
        }
        return "";
    }

    /**
     * 获取单选答案
     *
     * @param data
     * @param options
     * @return
     */
    private static JSONArray getSingleRightAnswer(String data, List<QuestionOptionDto> options) {
        Matcher m = RegexUtils.getMatcher(data, QuestionConstant.REGEX_MATCH_RULE.RIGHT_ANSWER_TAG);

        if (m.find()) {
            String result = data.substring(m.group(0).length());

            for (QuestionOptionDto option : options) {
                if (result.trim().toUpperCase().equals(option.getName())) {
                    return JSONArray.parseArray("[" + option.getNo() + "]");
                }
            }
        }
        return new JSONArray();
    }

    /**
     * 解析单选题答案
     *
     * @param data
     * @param options
     * @return
     */
    private static JSONArray getMutlRightAnswer(String data, List<QuestionOptionDto> options) {
        String[] spData = data.split("[" + splitStr + "]");
        if (spData != null && spData.length > 1) {
            String result = "";
            for (int i = 1; i < spData.length; i++) {
                result += spData[i];
            }

            StringBuffer answers = new StringBuffer();
            int ci = 0;
            for (Character answerChar : result.toCharArray()) {
                for (QuestionOptionDto option : options) {
                    if (answerChar.toString().trim().toUpperCase().equals(option.getName())) {
                        if (answers.length() > 0) {
                            answers.append(",");
                        }
                        answers.append(option.getNo());
                    }
                }
            }
            return JSONArray.parseArray("[" + answers.toString() + "]");
        }
        return new JSONArray();
    }

    /**
     * 解析完形填空正确答案
     *
     * @param data
     * @param options
     * @return
     */
    private static JSONArray getClozeRightAnswer(String data, List<QuestionOptionDto> options) {
        String[] spData = data.split("[" + splitStr + "]");
        if (spData != null && spData.length > 1) {
            String result = "";
            for (int i = 1; i < spData.length; i++) {
                result += spData[i];
            }

            StringBuffer answers = new StringBuffer();
            int ci = 0;
            for (Character answerChar : result.toCharArray()) {
                if (!StringUtils.isEmpty(answers.toString())) {
                    answers.append(",");
                }
                answers.append(QuestionConstant.OPTION_ORDER.indexOf(answerChar) + 1);
            }
            return JSONArray.parseArray("[" + answers.toString() + "]");
        }
        return new JSONArray();
    }

    /**
     * 连线题答案处理
     *
     * @param data
     * @param options
     * @return
     */
    private static JSONArray getLinkRightAnswer(String data, List<QuestionOptionDto> options) {
        Matcher m = RegexUtils.getMatcher(data, QuestionConstant.REGEX_MATCH_RULE.RIGHT_ANSWER_TAG);
        JSONArray result = new JSONArray();

        if (m.find()) {
            String answerData = data.substring(m.group(0).length());
            //[{source:1,target:2},{source:1,target:2}]
            String[] spData = answerData.split("[,，、.。．]");
            if (spData != null && spData.length > 1) {
                for (int i = 0; i < spData.length; i++) {
                    JSONObject link = new JSONObject();
                    String[] links = spData[i].split("[-]");
                    try {
                        link.put("source", Integer.parseInt(links[0].trim()));
                    } catch (Exception ex) {
                        link.put("source", 0);
                    }
                    try {
                        link.put("target", Integer.parseInt(links[1].trim()));
                    } catch (Exception ex) {
                        link.put("target", 0);
                    }
                    result.add(link);
                }
                return result;
            }
        }
        return result;
    }

    /**
     * 填空题题干处理
     *
     * @param title
     * @return
     */
    private static String formatBlankQuestionSem(String title) {
        title = title.replaceAll("[_]{4,}", "____");//将四个及四个以上的下划线认定为空，统一处理成四个下划线
        return title;
    }

    /**
     * 获取填空题答案
     *
     * @param data
     * @return
     */
    private static JSONArray getBlankRightAnswer(String data) {
        //[{no:1,content:''},{no:2,content:''}]
        if (!StringUtils.isEmpty(data)) {
            Matcher m = RegexUtils.getMatcher(data, QuestionConstant.REGEX_MATCH_RULE.RIGHT_ANSWER_TAG);
            if (m.find()) {
                String result = "";
                result = data.substring(m.group(0).length());

                String[] answerOris = result.trim().replaceAll("＃", "#").split("##");
                JSONArray answers = new JSONArray();
                for (int i = 0; i < answerOris.length; i++) {
                    JSONObject answer = new JSONObject();
                    answer.put("no", i + 1);
                    answer.put("content", answerOris[i].trim());
                    answers.add(answer);
                }
                return answers;
            }

        }
        return new JSONArray();
    }

    /**
     * 获取解答题正确答案
     *
     * @param data
     * @return
     */
    private static JSONObject getJdRightAnswer(String data) {
        JSONObject r = new JSONObject();
        if (!StringUtils.isEmpty(data)) {
            Matcher m = RegexUtils.getMatcher(data, QuestionConstant.REGEX_MATCH_RULE.RIGHT_ANSWER_TAG);
            if (m.find()) {
                String result = "";
                result = data.substring(m.group(0).length());
                r.put("content", result);
                return r;
            }

        }

        return r;
    }

    /**
     * 获取判断题正确答案
     *
     * @param data
     * @return
     */
    private static JSONObject getJudgeRightAnswer(String data) {
        JSONObject r = new JSONObject();
        Matcher m = RegexUtils.getMatcher(data, QuestionConstant.REGEX_MATCH_RULE.RIGHT_ANSWER_TAG);

        if (m.find()) {
            String result = data.substring(m.group(0).length());

            if (RegexUtils.Match(result.trim(), QuestionConstant.REGEX_MATCH_RULE.JUDGE_RIGHT_ANSWER)) {
                r.put("content", true);
                return r;
            } else if (RegexUtils.Match(result.trim(), QuestionConstant.REGEX_MATCH_RULE.JUDGE_WRONG_ANSWER)) {
                r.put("content", false);
                return r;
            }

        }
        return r;
    }

    /**
     * 解析
     *
     * @param data
     * @return
     */
    private static String getAnalysis(String data) {
        if (!StringUtils.isEmpty(data)) {
            Matcher m = RegexUtils.getMatcher(data, QuestionConstant.REGEX_MATCH_RULE.ANALYSIS_TAG);
            if (m.find()) {
                String result = data.substring(m.group(0).length());
                return result.trim();
            }

        }
        return "";
    }

    /**
     * 付费解析
     *
     * @param data
     * @return
     */
    private static String getAnalysisPay(String data) {
        if (!StringUtils.isEmpty(data)) {
            Matcher m = RegexUtils.getMatcher(data, QuestionConstant.REGEX_MATCH_RULE.ANALYSIS_PAY_TAG);
            if (m.find()) {
                String result = data.substring(m.group(0).length());
                return result.trim();
            }

        }
        return "";
    }

    /**
     * 考点解析
     *
     * @param data
     * @return
     */
    private static String getExamPoint(String data) {
        if (!StringUtils.isEmpty(data)) {
            Matcher m = RegexUtils.getMatcher(data, QuestionConstant.REGEX_MATCH_RULE.EXAM_POINT_TAG);
            if (m.find()) {
                String result = data.substring(m.group(0).length());
                return result.trim();
            }

        }
        return "";
    }

    /**
     * 视频解析地址
     *
     * @param data
     * @return
     */
    private static String getAnalysisVideo(String data) {
        if (!StringUtils.isEmpty(data)) {
            Matcher m = RegexUtils.getMatcher(data, QuestionConstant.REGEX_MATCH_RULE.VIDEO_ANALYSIS_TAG);
            if (m.find()) {
                String result = data.substring(m.group(0).length());
                return result.trim();
            }

        }
        return "";
    }

    /**
     * 解析难度
     *
     * @param data
     * @return
     */
    private static int getDifficulty(String data) {
        if (!StringUtils.isEmpty(data)) {
            Matcher m = RegexUtils.getMatcher(data, QuestionConstant.REGEX_MATCH_RULE.DIFFICULT_TAG);
            if (m.find()) {
                String result = data.substring(m.group(0).length());
                int dresult = 0;
                try {
                    dresult = Integer.valueOf(result.trim());
                } catch (Exception ex) {

                }
                return dresult;
            }

        }
        return 0;
    }

    /**
     * 判断是否是选项，是的话返回选项对象
     *
     * @param data
     * @return
     */
    private static QuestionOptionDto checkIsOptions(String data) {
        Matcher m = RegexUtils.getMatcher(data, QuestionConstant.REGEX_MATCH_RULE.OPTION_START);
        if (m.find()) {
            if (m.group(0).length() < data.length()) {
                QuestionOptionDto option = new QuestionOptionDto();
                String result = data.substring(m.group(0).length());
                option.setName(data.substring(0, 1).toUpperCase());
                option.setContent(result);
                return option;
            } else {
                return null;
            }
        }
        return null;
    }


    /**
     * 判断是否是完形填空选项，是的话返回选项对象
     *
     * @param data
     * @return
     */
    public static QuestionOptionDto checkIsClozeOptions(String data) {
        QuestionOptionDto clozeOption = new QuestionOptionDto();

        List<QuestionOptionDto> options = new ArrayList<>();
        Matcher m = RegexUtils.getMatcher(data, QuestionConstant.REGEX_MATCH_RULE.CLOZE_OPTION_START);
        if (m.find()) {
            if (m.group(0).length() < data.length()) {
                clozeOption.setName(m.group(0).trim().substring(0, 1));
                data = data.replaceAll(QuestionConstant.REGEX_MATCH_RULE.CLOZE_OPTION_START, "");

                m = RegexUtils.getMatcher(data, QuestionConstant.REGEX_MATCH_RULE.CLOZE_OPTION_CHILD_START);

                List<String> postions = new ArrayList<>();
                while (m.find()) {
                    postions.add(m.start() + "-" + m.end());
                    QuestionOptionDto option = new QuestionOptionDto();
                    option.setName(m.group(0).trim().substring(0, 1).toUpperCase());
                    options.add(option);
                }

                for (int i = 0; i < postions.size(); i++) {
                    Integer start = Integer.valueOf(postions.get(i).split("-")[0]);
                    Integer end = Integer.valueOf(postions.get(i).split("-")[1]);

                    String result = "";
                    if (i == postions.size() - 1) {
                        result = data.substring(end);
                    } else {
                        Integer nextStart = Integer.valueOf(postions.get(i + 1).split("-")[0]);
                        result = data.substring(end, nextStart - 1);
                    }
                    QuestionOptionDto option = options.get(i);
                    option.setNo(i + 1);
                    option.setContent(result.trim());
                }
                clozeOption.setChilds(options);
                return clozeOption;
            } else {
                return null;
            }
        }
        return null;
    }

    /**
     * 检查表格类选项
     *
     * @param data
     * @return
     */
    private static List<QuestionOptionDto> checkIsTableOptions(String data) {
        //选项：{source:[{no:1,content:''},{no:2,content:''}],target:[{no:1,content:''},{no:2,content:''}]}
        List<QuestionOptionDto> result = new ArrayList<>();
        Matcher m = RegexUtils.getMatcher(data, QuestionConstant.REGEX_MATCH_RULE.TABLE_OPTION_START);
        if (m.find()) {
            List<String> sources = new ArrayList<>();
            List<String> targets = new ArrayList<>();

            Document doc = Jsoup.parse(data);
            Elements rows = doc.select("tr");
            for (Element row : rows) {
                Elements cols = row.select("td");
                if (cols.size() > 0) {
                    if (cols.size() > 2) {
                        sources.add(cols.get(cols.size() - 2).html());
                        targets.add(cols.get(cols.size() - 1).html());
                        continue;
                    } else if (cols.size() == 1) {
                        sources.add(cols.get(0).html());
                        targets.add("");
                        continue;
                    }
                }
                sources.add("");
                targets.add("");
            }
            for (int i = 0; i < sources.size(); i++) {
                QuestionOptionDto option = new QuestionOptionDto();
                option.setType("source");
                option.setNo(i + 1);
                option.setContent(sources.get(i));
                result.add(option);
            }
            for (int i = 0; i < sources.size(); i++) {
                QuestionOptionDto option = new QuestionOptionDto();
                option.setType("target");
                option.setNo(i + 1);
                option.setContent(targets.get(i));
                result.add(option);
            }
            return result;
        }
        return null;
    }

    /**
     * 检测试题格式是否正确
     *
     * @param questions
     */
    private static void checkQuestionFormat(List<QuestionDto> questions) {
        for (QuestionDto question : questions) {
            checkQuestionFormat(question);
        }
    }

    /**
     * 判断试题数据格式是否正确
     *
     * @param question
     */
    public static void checkQuestionFormat(QuestionDto question) {
        String errorMsg = null;
        if (question.getDifficult() == null) {
            question.setDifficult(3);
        }
        Integer questionType = question.getBasicQuestionType();
        if (questionType.equals(QuestionConstant.TYPE.SINGLE))//单选
        {
            JSONArray rightAnswer = (JSONArray) question.getRightAnswer();
            if (question.getOptions() == null || (question.getOptions().size() == 0)) {
                addError(question, "题目未包含任何选项信息");
                return;
            }
            if (rightAnswer.size() == 0) {
                addError(question, "答案信息不完整");
                return;
            }
            if (isOptionsDupline(question)) {
                addError(question, "选项标识重复");
                return;
            }
        } else if (questionType.equals(QuestionConstant.TYPE.MUL))//多选
        {
            JSONArray rightAnswer = (JSONArray) question.getRightAnswer();
            if (question.getOptions() == null || (question.getOptions().size() == 0)) {
                addError(question, "题目未包含任何选项信息");
                return;
            }
            if (rightAnswer.size() == 0) {
                addError(question, "答案信息不完整");
                return;
            }
            if (isOptionsDupline(question)) {
                addError(question, "选项标识重复");
                return;
            }
        } else if (questionType.equals(QuestionConstant.TYPE.BLANK))//填空
        {
            JSONArray rightAnswer = (JSONArray) question.getRightAnswer();
            if (rightAnswer.size() == 0) {
                addError(question, "答案信息不完整");
                return;
            }

            Matcher matcher = RegexUtils.getMatcher(question.getTitle(), QuestionConstant.REGEX_MATCH_RULE.BLANK_SELECT);
            int blankCount = 0;
            while (matcher.find()) {
                blankCount++;
            }
            if (blankCount == 0) {
                addError(question, "题干中未找到填空信息");
                return;
            }
            if (rightAnswer.size() != blankCount) {
                addError(question, "题干中的填空数与答案数量不匹配");
                return;
            }
        } else if (questionType.equals(QuestionConstant.TYPE.JUDGE))//判断
        {
            JSONObject rightAnswer = (JSONObject) question.getRightAnswer();
            if (!rightAnswer.containsKey("content")) {
                addError(question, "答案信息不完整");
                return;
            }
        } else if (questionType.equals(QuestionConstant.TYPE.JIEDA))//解答\作文
        {
            JSONObject rightAnswer = (JSONObject) question.getRightAnswer();
            if (!rightAnswer.containsKey("content")) {
                addError(question, "答案信息不完整");
                return;
            }
        } else if (questionType.equals(QuestionConstant.TYPE.ORDER))//排序
        {
            JSONArray rightAnswer = (JSONArray) question.getRightAnswer();
            if (question.getOptions() == null || (question.getOptions().size() == 0)) {
                addError(question, "题目未包含任何选项信息");
                return;
            }
            if (rightAnswer.size() == 0) {
                addError(question, "答案信息不完整");
                return;
            }
            if (isOptionsDupline(question)) {
                addError(question, "选项标识重复");
                return;
            }
            if (rightAnswer.size() != question.getOptions().size()) {
                addError(question, "选项数与答案数量不匹配");
                return;
            }
        }
        question.setDataRight(true);
    }

    /**
     * 插入试题错误信息
     *
     * @param question
     * @param errorMsg
     */
    private static void addError(QuestionDto question, String errorMsg) {
        question.setDataRight(false);
        question.setDataErrorMsg(errorMsg);
    }

    /**
     * 判断是否有重复标识选项
     *
     * @param question
     * @return
     */
    private static Boolean isOptionsDupline(QuestionDto question) {
        Map<String, Integer> optionsMap = new HashMap<>();
        for (QuestionOptionDto option : question.getOptions()) {
            if (optionsMap.containsKey(option.getName())) {
                return true;
            } else {
                optionsMap.put(option.getName(), 1);
            }
        }
        return false;
    }

    /**
     * 判题
     *
     * @param type        试题类型
     * @param rightAnswer 正确答案
     * @param userAnswer  用户答案
     * @return
     */
    public static AnswerResultDto checkAnswer(Integer type, String rightAnswer, String userAnswer) {
        AnswerResultDto answerResultDto = null;
        if (type.equals(QuestionConstant.TYPE.SINGLE)) {
            answerResultDto = checkAnswerSelect(rightAnswer, userAnswer);
        } else if (type.equals(QuestionConstant.TYPE.MUL)) {
            answerResultDto = checkAnswerSelect(rightAnswer, userAnswer);
        } else if (type.equals(QuestionConstant.TYPE.BLANK)) {
            answerResultDto = checkAnswerBlank(rightAnswer, userAnswer);
        } else if (type.equals(QuestionConstant.TYPE.JUDGE)) {
            answerResultDto = checkAnswerJudge(rightAnswer, userAnswer);
        } else if (type.equals(QuestionConstant.TYPE.LINK)) {
            answerResultDto = checkAnswerLink(rightAnswer, userAnswer);
        } else if (type.equals(QuestionConstant.TYPE.ORDER)) {
            answerResultDto = checkAnswerOrder(rightAnswer, userAnswer);
        } else if (type.equals(QuestionConstant.TYPE.MATCH)) {
            answerResultDto = checkAnswerMatch(rightAnswer, userAnswer);
        } else {
            throw new XhException("不支持判题的提醒");
        }
        return answerResultDto;
    }

    /**
     * 单选、多选判题（多选判定部分正确，比正确答案少且都正确）
     *
     * @param rightAnswer
     * @param userAnswer
     * @return
     */
    private static AnswerResultDto checkAnswerSelect(String rightAnswer, String userAnswer) {
        AnswerResultDto answerResultDto = new AnswerResultDto();
        try {
            JSONArray rightAnswerJson = null;
            try {
                rightAnswerJson = JSONArray.parseArray(rightAnswer);
            } catch (Exception e) {
                rightAnswerJson = new JSONArray();
            }
            JSONArray userAnswerJson = null;
            try {
                userAnswerJson = JSONArray.parseArray(userAnswer);
            } catch (Exception e) {
                userAnswerJson = new JSONArray();
            }
            answerResultDto.setTotalBlankCount(rightAnswerJson.size());
            if (userAnswerJson.size() == 0) {
                return answerResultDto;
            } else {
                answerResultDto.setResult(QuestionConstant.ANSWER_RESULT.WRONG);
            }

            answerResultDto.setTotalBlankCount(rightAnswerJson.size());
            if (StringUtils.isEmpty(userAnswer) || rightAnswerJson.size() == 0) {
                return answerResultDto;
            }

            //多答了答案，直接判错
            if (rightAnswerJson.size() < userAnswerJson.size()) {
                answerResultDto.setResult(QuestionConstant.ANSWER_RESULT.WRONG);
                return answerResultDto;
            }
            int rightAnswerCount = rightAnswerJson.size();
            int rightCount = 0;
            //循环比对用户提交的答案
            for (int i = 0; i < userAnswerJson.size(); i++) {
                int userSel = userAnswerJson.getIntValue(i);
                inner:
                for (int j = rightAnswerJson.size() - 1; j >= 0; j--) {
                    int rightSel = rightAnswerJson.getIntValue(j);
                    if (userSel == rightSel) {
                        //比对过的答案去掉，避免用户提交答案重复导致判题错误
                        rightAnswerJson.remove(j);
                        rightCount++;
                        break inner;
                    }
                }
            }
            answerResultDto.setTotalRightBlankCount(rightCount);
            if (rightCount == 0) {
                answerResultDto.setResult(QuestionConstant.ANSWER_RESULT.WRONG);
            } else if (rightCount != rightAnswerCount) {
                answerResultDto.setResult(QuestionConstant.ANSWER_RESULT.PART_RIGHT);
            } else {
                answerResultDto.setRight(true);
                answerResultDto.setResult(QuestionConstant.ANSWER_RESULT.RIGHT);
            }
        } catch (Exception ex) {
        }
        return answerResultDto;
    }

    /**
     * 填空题判题（判定部分空正确性）
     *
     * @param rightAnswer
     * @param userAnswer
     * @return
     */
    private static AnswerResultDto checkAnswerBlank(String rightAnswer, String userAnswer) {
        AnswerResultDto answerResultDto = new AnswerResultDto();
        try {
            JSONArray rightAnswerJson = null;
            try {
                rightAnswerJson = JSONArray.parseArray(rightAnswer);
            } catch (Exception e) {
                rightAnswerJson = new JSONArray();
            }
            JSONArray userAnswerJson = null;
            try {
                userAnswerJson = JSONArray.parseArray(userAnswer);
            } catch (Exception e) {
                userAnswerJson = new JSONArray();
            }
            answerResultDto.setTotalBlankCount(rightAnswerJson.size());
            if (userAnswerJson.size() == 0) {
                return answerResultDto;
            } else {
                answerResultDto.setResult(QuestionConstant.ANSWER_RESULT.WRONG);
            }

            answerResultDto.setTotalBlankCount(rightAnswerJson.size());
            if (StringUtils.isEmpty(userAnswer) || rightAnswerJson.size() == 0) {
                return answerResultDto;
            }

            //多答了答案，直接判错
            if (rightAnswerJson.size() < userAnswerJson.size()) {
                answerResultDto.setResult(QuestionConstant.ANSWER_RESULT.WRONG);
                return answerResultDto;
            }
            int rightAnswerCount = rightAnswerJson.size();
            int rightCount = 0;
            //循环比对用户提交的答案
            outter:
            for (int i = 0; i < userAnswerJson.size(); i++) {
                Integer userAnswerNo = userAnswerJson.getJSONObject(i).getInteger("no");
                String userAnswerContent = userAnswerJson.getJSONObject(i).getString("content");
                inner:
                for (int j = 0; j < rightAnswerJson.size(); j++) {
                    Integer rightAnswerNo = rightAnswerJson.getJSONObject(j).getInteger("no");
                    if (!userAnswerNo.equals(rightAnswerNo)) {
                        continue inner;
                    }
                    //拆分一空多答案
                    String[] acs = rightAnswerJson.getJSONObject(j).getString("content").trim().split("\\*\\*");
                    String ua = userAnswerContent == null ? "" : userAnswerContent.trim();
                    for (String ac : acs) {
                        //判断作答结果是否正确
                        if (formatBlankAnswer(ac).equals(formatBlankAnswer(ua))) {
                            rightCount++;
                            continue outter;
                        }
                    }
                }
            }
            answerResultDto.setTotalRightBlankCount(rightCount);
            if (rightCount == 0) {
                answerResultDto.setResult(QuestionConstant.ANSWER_RESULT.WRONG);
            } else if (rightCount != rightAnswerCount) {
                answerResultDto.setResult(QuestionConstant.ANSWER_RESULT.PART_RIGHT);
            } else {
                answerResultDto.setRight(true);
                answerResultDto.setResult(QuestionConstant.ANSWER_RESULT.RIGHT);
            }
        } catch (Exception ex) {
        }
        return answerResultDto;
    }

    /**
     * 判断题判题（没有部分正确）
     *
     * @param rightAnswer
     * @param userAnswer
     * @return
     */
    private static AnswerResultDto checkAnswerJudge(String rightAnswer, String userAnswer) {
        AnswerResultDto answerResultDto = new AnswerResultDto();
        try {
            JSONObject rightAnswerJson = null;
            try {
                rightAnswerJson = JSONObject.parseObject(rightAnswer);
            } catch (Exception e) {
                rightAnswerJson = new JSONObject();
            }
            JSONObject userAnswerJson = null;
            try {
                userAnswerJson = JSONObject.parseObject(userAnswer);
            } catch (Exception e) {
                userAnswerJson = new JSONObject();
            }
            answerResultDto.setTotalBlankCount(rightAnswerJson.size());
            if (!userAnswerJson.containsKey("content")) {
                return answerResultDto;
            } else {
                answerResultDto.setResult(QuestionConstant.ANSWER_RESULT.WRONG);
            }

            answerResultDto.setTotalBlankCount(rightAnswerJson.containsKey("content") ? 1 : 0);
            if (StringUtils.isEmpty(userAnswer) || !rightAnswerJson.containsKey("content")) {
                return answerResultDto;
            }

            //多答了答案，直接判错
            if (rightAnswerJson.size() < userAnswerJson.size()) {
                answerResultDto.setResult(QuestionConstant.ANSWER_RESULT.WRONG);
                return answerResultDto;
            }

            Boolean rightAnswerContent = rightAnswerJson.getBoolean("content");
            Boolean userAnswerContent = userAnswerJson.getBoolean("content");

            if (!userAnswerContent.equals(rightAnswerContent)) {
                answerResultDto.setResult(QuestionConstant.ANSWER_RESULT.WRONG);
            } else {
                answerResultDto.setRight(true);
                answerResultDto.setTotalRightBlankCount(1);
                answerResultDto.setResult(QuestionConstant.ANSWER_RESULT.RIGHT);
            }
        } catch (Exception ex) {
        }
        return answerResultDto;
    }

    /**
     * 排序题判题（没有部分正确）
     *
     * @param rightAnswer
     * @param userAnswer
     * @return
     */
    private static AnswerResultDto checkAnswerOrder(String rightAnswer, String userAnswer) {
        AnswerResultDto answerResultDto = new AnswerResultDto();
        try {
            JSONArray rightAnswerJson = null;
            try {
                rightAnswerJson = JSONArray.parseArray(rightAnswer);
            } catch (Exception e) {
                rightAnswerJson = new JSONArray();
            }
            JSONArray userAnswerJson = null;
            try {
                userAnswerJson = JSONArray.parseArray(userAnswer);
            } catch (Exception e) {
                userAnswerJson = new JSONArray();
            }
            answerResultDto.setTotalBlankCount(1);
            if (userAnswerJson.size() == 0) {
                return answerResultDto;
            } else {
                answerResultDto.setResult(QuestionConstant.ANSWER_RESULT.WRONG);
            }

            if (StringUtils.isEmpty(userAnswer) || rightAnswerJson.size() == 0) {
                return answerResultDto;
            }
            int rightAnswerCount = rightAnswerJson.size();

            //多答了答案，直接判错
            if (rightAnswerCount == 0 || rightAnswerJson.size() != userAnswerJson.size()) {
                answerResultDto.setResult(QuestionConstant.ANSWER_RESULT.WRONG);
                return answerResultDto;
            }
            int rightCount = 0;
            //循环比对用户提交的答案
            for (int i = 0; i < userAnswerJson.size(); i++) {
                int userSel = userAnswerJson.getIntValue(i);
                int rightSel = rightAnswerJson.getIntValue(i);
                if (userSel == rightSel) {
                    rightCount++;
                }
            }

            if (rightCount != rightAnswerCount) {
                answerResultDto.setResult(QuestionConstant.ANSWER_RESULT.WRONG);
            } else {
                answerResultDto.setRight(true);
                answerResultDto.setTotalRightBlankCount(1);
                answerResultDto.setResult(QuestionConstant.ANSWER_RESULT.RIGHT);
            }
        } catch (Exception ex) {
        }
        return answerResultDto;
    }

    /**
     * 连线题（判定部分正确，比正确答案少且都正确）
     *
     * @param rightAnswer
     * @param userAnswer
     * @return
     */
    private static AnswerResultDto checkAnswerLink(String rightAnswer, String userAnswer) {
        AnswerResultDto answerResultDto = new AnswerResultDto();
        try {
            JSONArray rightAnswerJson = null;
            try {
                rightAnswerJson = JSONArray.parseArray(rightAnswer);
            } catch (Exception e) {
                rightAnswerJson = new JSONArray();
            }
            JSONArray userAnswerJson = null;
            try {
                userAnswerJson = JSONArray.parseArray(userAnswer);
            } catch (Exception e) {
                userAnswerJson = new JSONArray();
            }
            answerResultDto.setTotalBlankCount(rightAnswerJson.size());
            if (userAnswerJson.size() == 0) {
                return answerResultDto;
            } else {
                answerResultDto.setResult(QuestionConstant.ANSWER_RESULT.WRONG);
            }

            answerResultDto.setTotalBlankCount(rightAnswerJson.size());
            if (StringUtils.isEmpty(userAnswer) || rightAnswerJson.size() == 0) {
                return answerResultDto;
            }

            //多答了答案，直接判错
            if (rightAnswerJson.size() < userAnswerJson.size()) {
                answerResultDto.setResult(QuestionConstant.ANSWER_RESULT.WRONG);
                return answerResultDto;
            }
            int rightAnswerCount = rightAnswerJson.size();
            int rightCount = 0;
            //循环比对用户提交的答案
            for (int i = 0; i < userAnswerJson.size(); i++) {
                int userSource = userAnswerJson.getJSONObject(i).getIntValue("source");
                inner:
                for (int j = rightAnswerJson.size() - 1; j >= 0; j--) {
                    int rightSource = rightAnswerJson.getJSONObject(j).getIntValue("source");
                    if (userSource == rightSource) {
                        //比对过的答案去掉，避免用户提交答案重复导致判题错误
                        int userTarget = userAnswerJson.getJSONObject(i).getIntValue("target");
                        int rightTarget = rightAnswerJson.getJSONObject(j).getIntValue("target");
                        if (userTarget == rightTarget) {
                            rightAnswerJson.remove(j);
                            rightCount++;
                            break inner;
                        }
                    }
                }
            }
            answerResultDto.setTotalRightBlankCount(rightCount);
            if (rightCount == 0) {
                answerResultDto.setResult(QuestionConstant.ANSWER_RESULT.WRONG);
            } else if (rightCount != rightAnswerCount) {
                answerResultDto.setResult(QuestionConstant.ANSWER_RESULT.PART_RIGHT);
            } else {
                answerResultDto.setRight(true);
                answerResultDto.setResult(QuestionConstant.ANSWER_RESULT.RIGHT);
            }
        } catch (Exception ex) {
        }
        return answerResultDto;

    }

    /**
     * 匹配题判题（没有部分正确）
     *
     * @param rightAnswer
     * @param userAnswer
     * @return
     */
    private static AnswerResultDto checkAnswerMatch(String rightAnswer, String userAnswer) {
        return checkAnswerOrder(rightAnswer, userAnswer);
    }

    /**
     * 格式化填空答案
     *
     * @param answer
     * @return
     */
    private static String formatBlankAnswer(String answer) {
        //去除html标签
        String cleanAnswer = HtmlUtils.cleanExceptImg(answer);
        //去除图片元素
        String compareAnswer = HtmlUtils.replaceTag2TagAttr(cleanAnswer, "img", "data-latex");
        //全角转半角
        compareAnswer = StringUtils.toDBC(compareAnswer);
        //去除空格
        compareAnswer = compareAnswer.replace(" ", "");
        //中文标点转英文标点。；，？！、“”‘’转.;,?!""''
        compareAnswer = StringUtils.replaceChsCharToEng(compareAnswer);
        return compareAnswer;
    }

    /**
     * 计算题目选项的排列方式
     *
     * @param optionDtos
     */
    public static Integer calculateOptionArrangements(List<QuestionOptionDto> optionDtos) {
        if(CollectionUtils.isEmpty(optionDtos)){
            return null;
        }
        // 获取试题的选项的最大长度
        Integer maxLength = 0;
        for (QuestionOptionDto optionDto : optionDtos) {
            optionDto.setContent(StringUtils.removeStartAndEndBlank(optionDto.getContent()));
            Integer length = getHtmlWidth(optionDto.getName() + "." + optionDto.getContent());
            if(length > maxLength){
                maxLength = length;
            }
        }
        // 一行四个选项
        if (maxLength < QuestionConstant.OPTION_ARRANGEMENTS.MAX_LENGTH_FOUR) {
            return QuestionConstant.OPTION_ARRANGEMENTS.FOUR;
        }
        // 一行俩个选项
        if (maxLength <= QuestionConstant.OPTION_ARRANGEMENTS.MAX_LENGTH_TWO) {
            return QuestionConstant.OPTION_ARRANGEMENTS.TWO;
        }
        // 一行一个选项
        if (maxLength <= QuestionConstant.OPTION_ARRANGEMENTS.MAX_LENGTH_ONE) {
            return QuestionConstant.OPTION_ARRANGEMENTS.ONE;
        }
        return 0;
    }

    /**
     * 计算题目选项的排列方式
     *
     * @param question
     */
    public static void calculateOptionArrangements(Question question) {
        if (StringUtils.isEmpty(question.getOptionContent())) {
            return;
        }
        // 获取试题的选项的最大长度
        JSONArray array = JSON.parseArray(question.getOptionContent());
        Integer maxLength = 0;
        for (int i = 0; i < array.size(); i++) {
            JSONObject option = array.getJSONObject(i);
            String content = StringUtils.removeStartAndEndBlank(option.getString("content"));
            option.put("content", content);
            Integer length = getHtmlWidth(option.getString("name")+"."+content);
            if(length > maxLength){
                maxLength = length;
            }
        }
        // 一行四个选项
        if (maxLength <= QuestionConstant.OPTION_ARRANGEMENTS.PAPER_MAX_LENGTH_FOUR) {
            question.setOptionArrangements(QuestionConstant.OPTION_ARRANGEMENTS.FOUR);
            return;
        }
        // 一行俩个选项
        if (maxLength <= QuestionConstant.OPTION_ARRANGEMENTS.MAX_LENGTH_TWO) {
            question.setOptionArrangements(QuestionConstant.OPTION_ARRANGEMENTS.TWO);
            return;
        }
        // 一行一个选项
        question.setOptionArrangements(QuestionConstant.OPTION_ARRANGEMENTS.ONE);
    }

    /**
     * 计算题目选项的排列方式
     *
     * @param optionDtos
     */
    public static Integer calculateOptionArrange(List<QuestionOptionDto> optionDtos) {
        if(CollectionUtils.isEmpty(optionDtos)){
            return null;
        }
        // 获取试题的选项的最大长度
        Integer maxLength = 0;
        for (QuestionOptionDto optionDto : optionDtos) {
            if (StringUtils.isEmpty(optionDto.getContent())) {
                continue;
            }
            optionDto.setContent(StringUtils.removeStartAndEndBlank(optionDto.getContent()));
            Integer length = getHtmlWidth(optionDto.getName()+"."+optionDto.getContent());
            if(length > maxLength){
                maxLength = length;
            }
        }
        // 一行四个选项
        if (maxLength < QuestionConstant.OPTION_ARRANGEMENTS.PAPER_MAX_LENGTH_FOUR) {
            return QuestionConstant.OPTION_ARRANGEMENTS.FOUR;
        }
        // 一行俩个选项
        if (maxLength <= QuestionConstant.OPTION_ARRANGEMENTS.PAPER_MAX_LENGTH_TWO) {
            return QuestionConstant.OPTION_ARRANGEMENTS.TWO;
        }
        // 一行一个选项
//        if (maxLength <= QuestionConstant.OPTION_ARRANGEMENTS.PAPER_MAX_LENGTH_ONE) {
//            return QuestionConstant.OPTION_ARRANGEMENTS.ONE;
//        }
        return QuestionConstant.OPTION_ARRANGEMENTS.ONE;
    }

    public static Integer getHtmlWidth(String html) {
        Document doc = Jsoup.parse(html);
        String text = doc.text();
        Integer length = text.length();
        if (RegexUtils.Match(text, PaperConstant.CHINESE)) {
            length*=3;
        }
        Integer imgLength = 0;
        for (Element element : doc.getElementsByTag("img")) {
            String widthStr = element.attr("width");
            if (!StringUtils.isEmpty(widthStr)) {
                Matcher matcher = RegexUtils.getMatcher(widthStr,"\\d+");
                if(matcher.find()){
                    String width = matcher.group();
                    imgLength += Integer.valueOf(width);
                }
            }else{
                String src = element.attr("src");
                if (!StringUtils.isEmpty(src)) {
                    try {
                        imgLength +=ImageIO.read(new URL(src)).getWidth();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }else{
                    continue;
                }
            }
        }
        return length + imgLength / 10;
    }

    /**
     * 获取试题的Html展示效果
     *
     * @param question
     * @param withAnswer
     * @return
     */
    public static String getQuestionHtml(QuestionDto question, Boolean withTitle, Boolean withAnswer, Boolean withAnalysis, Boolean withExamPoint) {
        if (question.getType() == 0) {
            return getEssayQuestionHtml(question, withTitle, withAnswer, withAnalysis, withExamPoint);
        }
        Integer questionType = _questionTypeRelationService.queryToolQuestionTypeByJyType(question.getSubjectId(), question.getType());
        question.setBasicQuestionType(questionType);
        String html;
        switch (questionType) {
            case 1:
                //单选题
                html = getSingleOrMulQuestionHtml(question, withTitle, withAnswer, withAnalysis, withExamPoint);
                break;
            case 2:
                //多选题
                html = getSingleOrMulQuestionHtml(question, withTitle, withAnswer, withAnalysis, withExamPoint);
                break;
            case 3:
                //填空题
                html = getBlankQuestionHtml(question, withTitle, withAnswer, withAnalysis, withExamPoint);
                break;
            case 4:
                //判断题
                html = getJudgeQuestionHtml(question, withTitle, withAnswer, withAnalysis, withExamPoint);
                break;
            case 5:
                //解答题
                html = getEssayQuestionHtml(question, withTitle, withAnswer, withAnalysis, withExamPoint);
                break;
            case 6:
                //排序题
                html = getOrderQuestionHtml(question, withTitle, withAnswer, withAnalysis, withExamPoint);
                break;
            case 7:
                //连线题
                html = getLinkQuestionHtml(question, withTitle, withAnswer, withAnalysis, withExamPoint);
                break;
            case 8:
                //匹配题
                html = getMatchQuestionHtml(question, withTitle, withAnswer, withAnalysis, withExamPoint);
                break;
            case 9:
                //阅读理解
                html = getReadingQuestionHtml(question, withTitle, withAnswer, withAnalysis, withExamPoint);
                break;
            case 10:
                //完形填空
                html = getClozeQuestionHtml(question, withTitle, withAnswer, withAnalysis, withExamPoint);
                break;
            case 11:
                //综合题
                html = getCombQuestionHtml(question, withTitle, withAnswer, withAnalysis, withExamPoint);
                break;
            default:
                html = getEssayQuestionHtml(question, withTitle, withAnswer, withAnalysis, withExamPoint);
                break;
        }
        return html;
    }


    /**
     * 获取单选html
     *
     * @param question
     * @param withAnswer
     * @param withAnalysis
     * @param withExamPoint
     * @return
     */
    public static String getSingleOrMulQuestionHtml(QuestionDto question, Boolean withTitle, Boolean withAnswer, Boolean withAnalysis, Boolean withExamPoint) {
        StringBuffer html = new StringBuffer();
//        html.append("(").append(getQuestionTypeChinese(question.getBasicQuestionType())).append(")");
        html.append(question.getQuestionNo());
        if (withTitle) {
            html.append(question.getTitle()).append("<br/>");

            if (question.getBasicQuestionType().equals(QuestionConstant.TYPE.SINGLE)
                    || question.getBasicQuestionType().equals(QuestionConstant.TYPE.MUL)) {
                JSONArray options = (JSONArray) question.getOption();
                if (null != options) {
                    List<QuestionOptionDto> optionDtos = JSONObject.parseArray(question.getOption().toJSONString(), QuestionOptionDto.class);
                    Integer optionNum = QuestionUtils.calculateOptionArrange(optionDtos);
                    for (int i = 0; i < options.size(); i++) {
                        JSONObject option = options.getJSONObject(i);
                        String name = option.getString("name");
                        if (StringUtils.isEmpty(name)) {
                            name = option.getString("orderNo");
                        }
                        if (StringUtils.isEmpty(name)) {
                            int index = option.getIntValue("no");
                            name = QuestionConstant.OPTION_ORDER.substring(index - 1, index);
                        }
                        String content = option.getString("content");
                        if (optionNum == 1) {
                            html.append("<p style='width: 710pt'><span style='display:inline-block;width: 700pt'>");
                            html.append(name).append(".").append(content).append("</span></p>");
                        } else if (optionNum == 2) {
                            if (i % 2 == 0) {
                                html.append("<p style='width: 710pt'>");
                            }
                            html.append("<span style='display:inline-block;width: 350pt'>").append(name).append(".").append(content).append("</span>");
                            if ((i != 0 && i % 2 == 1) || i == options.size() - 1) {
                                html.append("</p>");
                            }
                        } else {
                            if (i % 4 == 0) {
                                html.append("<p style='width: 710pt'>");
                            }
                            html.append("<span style='display:inline-block;width: 175pt'>").append(name).append(".").append(content).append("</span>");
                            if ((i != 0 && i % 3 == 0) || i == options.size() - 1) {
                                html.append("</p>");
                            }
                        }
//                        // 一行四个选项
//                        if (optionNum == 4) {
//                            html.append("<p style='width:170px;float:left'>");
//                        }
                        // 一行俩个选项
//                        if (optionNum == 2) {
//                            html.append("<p style='width:340px;float:left'>");
//                        }
//                        if (optionNum == 1) {
//                            html.append("<p style='width:680px;float:left'>");
//                        }
//                        html.append(name).append(".").append(content).append("</p>");

//                        // 一行一个选项
//                        if (optionNum == 1) {
//                            html.append("<br/>");
//                        }
//
//                        if (i == options.size() - 1) {
//                            html.append("<br/>");
//                        }

                    }
                }
            }
        }
        if (withAnswer) {
            //答案
            if (question.getBasicQuestionType().equals(QuestionConstant.TYPE.SINGLE)
                    || question.getBasicQuestionType().equals(QuestionConstant.TYPE.MUL)) {
                JSONArray options = (JSONArray) question.getRightAnswer();
                html.append("答案：");
                if (null != options) {
                    for (int i = 0; i < options.size(); i++) {
                        JSONObject answer = options.getJSONObject(i);
                        String rightAnswer = answer.getString("content");
                        html.append(rightAnswer).append(".").append("<br/>");
                    }
                }
            }
        }
        //解析
        if (withAnalysis) {
            html.append("解析：").append(question.getAnalysis() == null ? "" : question.getAnalysis()).append("<br/>");
        }
        //考点分析
        if (withExamPoint) {
            html.append("考点分析：").append(question.getExamPoint() == null ? "" : question.getExamPoint()).append("<br/>");
        }
        return html.toString();
    }


    /**
     * 获取填空题html
     *
     * @param question
     * @param withAnswer
     * @param withAnalysis
     * @param withExamPoint
     * @return
     */
    public static String getBlankQuestionHtml(QuestionDto question, Boolean withTitle, Boolean withAnswer, Boolean withAnalysis, Boolean withExamPoint) {
        StringBuffer html = new StringBuffer();
//        html.append("(").append(getQuestionTypeChinese(question.getBasicQuestionType())).append(")");
        html.append(question.getQuestionNo());
        if (withTitle) {
            html.append(question.getTitle()).append("<br/>");
        }
        if (withAnswer) {
            //答案
            if (question.getBasicQuestionType().equals(QuestionConstant.TYPE.SINGLE)
                    || question.getBasicQuestionType().equals(QuestionConstant.TYPE.MUL)) {
                JSONArray options = (JSONArray) question.getRightAnswer();
                html.append("答案：");
                if (null != options) {
                    for (int i = 0; i < options.size(); i++) {
                        JSONObject answer = options.getJSONObject(i);
                        String rightAnswer = answer.getString("content");
                        html.append(rightAnswer).append(".").append("<br/>");
                    }
                }
            }
        }
        //解析
        if (withAnalysis) {
            html.append("解析：").append(question.getAnalysis() == null ? "" : question.getAnalysis()).append("<br/>");
        }
        //考点分析
        if (withExamPoint) {
            html.append("考点分析：").append(question.getExamPoint() == null ? "" : question.getExamPoint()).append("<br/>");
        }
        return html.toString();
    }

    /**
     * 获取判断题html
     *
     * @param question
     * @param withAnswer
     * @param withAnalysis
     * @param withExamPoint
     * @return
     */
    public static String getJudgeQuestionHtml(QuestionDto question, Boolean withTitle, Boolean withAnswer, Boolean withAnalysis, Boolean withExamPoint) {
        StringBuffer html = new StringBuffer();
//        html.append("(").append(getQuestionTypeChinese(question.getBasicQuestionType())).append(")");
        html.append(question.getQuestionNo());
        if (withTitle) {
            html.append(question.getTitle()).append("___").append("<br/>");
        }
        if (withAnswer) {
            //答案
            if (question.getBasicQuestionType().equals(QuestionConstant.TYPE.JUDGE)) {
                JSONArray options = (JSONArray) question.getRightAnswer();
                html.append("答案：");
                if (null != options) {
                    for (int i = 0; i < options.size(); i++) {
                        JSONObject answer = options.getJSONObject(i);
                        String rightAnswer = answer.getString("content");
                        if (rightAnswer.equals("正确")) {
                            html.append("√").append(".").append("<br/>");
                        } else {
                            html.append("×").append(".").append("<br/>");
                        }
                    }
                }
            }
        }
        //解析
        if (withAnalysis) {
            html.append("解析：").append(question.getAnalysis() == null ? "" : question.getAnalysis()).append("<br/>");
        }
        //考点分析
        if (withExamPoint) {
            html.append("考点分析：").append(question.getExamPoint() == null ? "" : question.getExamPoint()).append("<br/>");
        }
        return html.toString();
    }

    /**
     * 获取解答题html
     *
     * @param question
     * @param withAnswer
     * @param withAnalysis
     * @param withExamPoint
     * @return
     */
    public static String getEssayQuestionHtml(QuestionDto question, Boolean withTitle, Boolean withAnswer, Boolean withAnalysis, Boolean withExamPoint) {
        StringBuffer html = new StringBuffer();
//        html.append("(").append(getQuestionTypeChinese(question.getBasicQuestionType())).append(")");
        html.append(question.getQuestionNo());
        if (withTitle) {
            if (question.getTitle().startsWith("<p>")) {
                question.setTitle(question.getTitle().replaceFirst("<p>", "").replaceFirst("</p>", ""));
            }
            html.append(question.getTitle()).append("<br/>");
        }
        if (withAnswer) {
            //答案
//            if (question.getBasicQuestionType().equals(QuestionConstant.TYPE.JIEDA)) {
            JSONArray options = (JSONArray) question.getRightAnswer();
            html.append("答案：");
            if (null != options) {
                for (int i = 0; i < options.size(); i++) {
                    JSONObject answer = options.getJSONObject(i);
                    String rightAnswer = answer.getString("content");
                    html.append(rightAnswer).append(".").append("<br/>");
                }
            }
//            }
        }
        //解析
        if (withAnalysis) {
            html.append("解析：").append(question.getAnalysis() == null ? "" : question.getAnalysis()).append("<br/>");
        }
        //考点分析
        if (withExamPoint) {
            html.append("考点分析：").append(question.getExamPoint() == null ? "" : question.getExamPoint()).append("<br/>");
        }
        return html.toString();
    }

    /**
     * 获取排序html
     *
     * @param question
     * @param withAnswer
     * @param withAnalysis
     * @param withExamPoint
     * @return
     */
    public static String getOrderQuestionHtml(QuestionDto question, Boolean withTitle, Boolean withAnswer, Boolean withAnalysis, Boolean withExamPoint) {
        StringBuffer html = new StringBuffer();
//        html.append("(").append(getQuestionTypeChinese(question.getBasicQuestionType())).append(")");
        html.append(question.getQuestionNo());
        if (withTitle) {
            html.append(question.getTitle()).append("<br/>");
        }
        //选项
        if (question.getBasicQuestionType().equals(QuestionConstant.TYPE.ORDER)) {
            JSONArray options = (JSONArray) question.getOption();
            for (int i = 0; i < options.size(); i++) {
                JSONObject option = options.getJSONObject(i);
                String name = option.getString("name");
                String content = option.getString("content");
                html.append(name).append(".").append(content).append("<br/>");
            }
        }
        if (withAnswer) {
            //答案
            if (question.getBasicQuestionType().equals(QuestionConstant.TYPE.ORDER)) {
                JSONArray options = (JSONArray) question.getRightAnswer();
                html.append("答案：");
                for (int i = 0; i < options.size(); i++) {
                    JSONObject answer = options.getJSONObject(i);
                    String rightAnswer = answer.getString("content");
                    html.append(rightAnswer).append(".").append("<br/>");
                }
            }
        }
        //解析
        if (withAnalysis) {
            html.append("解析：").append(question.getAnalysis() == null ? "" : question.getAnalysis()).append("<br/>");
        }
        //考点分析
        if (withExamPoint) {
            html.append("考点分析：").append(question.getExamPoint() == null ? "" : question.getExamPoint()).append("<br/>");
        }
        return html.toString();
    }

    /**
     * 获取连线题html
     *
     * @param question
     * @param withAnswer
     * @param withAnalysis
     * @param withExamPoint
     * @return
     */
    public static String getLinkQuestionHtml(QuestionDto question, Boolean withTitle, Boolean withAnswer, Boolean withAnalysis, Boolean withExamPoint) {
        StringBuffer html = new StringBuffer();
//        html.append("(").append(getQuestionTypeChinese(question.getBasicQuestionType())).append(")");
        html.append(question.getQuestionNo());
        if (withTitle) {
            html.append(question.getTitle()).append("<br/>");
        }
        //选项
        if (question.getBasicQuestionType().equals(QuestionConstant.TYPE.LINK)) {
            JSONArray options = (JSONArray) question.getOption();
            if (options.size() == 2) {
                JSONObject source = options.getJSONObject(0);
                JSONObject target = options.getJSONObject(1);

                JSONArray sourceChilds = source.getJSONArray("childs");
                JSONArray targetChilds = target.getJSONArray("childs");

                for (int i = 0; i < sourceChilds.size(); i++) {
                    JSONObject sourceOption = sourceChilds.getJSONObject(i);
                    JSONObject targetOption = targetChilds.getJSONObject(i);
                    String sourceContent = sourceOption.getString("content");
                    String targetContent = targetOption.getString("content");
                    html.append(sourceContent).append("&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ").append(targetContent).append("</br>");
                }
            }
        }
        if (withAnswer) {
            //答案
            if (question.getBasicQuestionType().equals(QuestionConstant.TYPE.LINK)) {
                JSONArray answers = (JSONArray) question.getRightAnswer();
                html.append("答案：");
                for (int i = 0; i < answers.size(); i++) {
                    JSONObject jsonObject = answers.getJSONObject(i);
                    JSONArray childs = jsonObject.getJSONArray("childs");
                    if (childs.size() == 2) {
                        JSONObject sourceAnswer = childs.getJSONObject(0);
                        JSONObject targetAnswer = childs.getJSONObject(1);

                        Integer sourceOrderNo = sourceAnswer.getInteger("orderNo");
                        Integer targetOrderNo = targetAnswer.getInteger("orderNo");
                        html.append(sourceOrderNo).append("——").append(targetOrderNo).append("</br>");
                    }

                }
            }
        }
        //解析
        if (withAnalysis) {
            html.append("解析：").append(question.getAnalysis() == null ? "" : question.getAnalysis()).append("<br/>");
        }
        //考点分析
        if (withExamPoint) {
            html.append("考点分析：").append(question.getExamPoint() == null ? "" : question.getExamPoint()).append("<br/>");
        }
        return html.toString();
    }

    /**
     * 获取匹配题html
     *
     * @param question
     * @param withAnswer
     * @param withAnalysis
     * @param withExamPoint
     * @return
     */
    public static String getMatchQuestionHtml(QuestionDto question, Boolean withTitle, Boolean withAnswer, Boolean withAnalysis, Boolean withExamPoint) {
        StringBuffer html = new StringBuffer();
//        html.append("(").append(getQuestionTypeChinese(question.getBasicQuestionType())).append(")");
        html.append(question.getQuestionNo());
        if (withTitle) {
            html.append(question.getTitle()).append("<br/>");
        }
        if (withAnswer) {
            //答案
            if (question.getBasicQuestionType().equals(QuestionConstant.TYPE.MATCH)) {
                JSONArray options = (JSONArray) question.getRightAnswer();
                html.append("答案：");
                for (int i = 0; i < options.size(); i++) {
                    JSONObject answer = options.getJSONObject(i);
                    String rightAnswer = answer.getString("content");
                    html.append(rightAnswer).append(".").append("<br/>");
                }
            }
        }
        //解析
        if (withAnalysis) {
            html.append("解析：").append(question.getAnalysis() == null ? "" : question.getAnalysis()).append("<br/>");
        }
        //考点分析
        if (withExamPoint) {
            html.append("考点分析：").append(question.getExamPoint() == null ? "" : question.getExamPoint()).append("<br/>");
        }
        return html.toString();
    }

    /**
     * 获取阅读理解html
     *
     * @param question
     * @param withAnswer
     * @param withAnalysis
     * @param withExamPoint
     * @return
     */
    public static String getReadingQuestionHtml(QuestionDto question, Boolean withTitle, Boolean withAnswer, Boolean withAnalysis, Boolean withExamPoint) {
        StringBuffer html = new StringBuffer();
//        html.append("(").append(getQuestionTypeChinese(question.getBasicQuestionType())).append(")");
        html.append(question.getQuestionNo());
        if (withTitle) {
            html.append(question.getTitle()).append("<br/>");

            //选项
            List<QuestionDto> childQuestion = _questionService.getQuestionChild(question.getId());
            String readingChildQuesHtml = getReadingChildQuesHtml(childQuestion);
            if (!StringUtils.isEmpty(readingChildQuesHtml)) {
                html.append(readingChildQuesHtml);
            }
        }
        if (withAnswer) {
            //答案
//            if (question.getType().equals(QuestionConstant.TYPE.READING)) {
            JSONArray options = (JSONArray) question.getRightAnswer();
            html.append("答案：");
            if (null != options) {
                String rightAnswerContent = "";
                for (int i = 0; i < options.size(); i++) {
                    JSONObject answer = options.getJSONObject(i);
                    String rightAnswer = answer.getString("content");
                    if ((i + 1) % 5 == 0) {
                        rightAnswerContent += rightAnswer + "&nbsp; &nbsp; ";
                    } else {
                        rightAnswerContent += rightAnswer;
                    }
                }
                if (!StringUtils.isEmpty(rightAnswerContent)) {
                    html.append(rightAnswerContent).append("<br/>");
                }
            }
//            }
        }
        //解析
        if (withAnalysis) {
            html.append("解析：").append(question.getAnalysis() == null ? "" : question.getAnalysis()).append("<br/>");
        }
        //考点分析
        if (withExamPoint) {
            html.append("考点分析：").append(question.getExamPoint() == null ? "" : question.getExamPoint()).append("<br/>");
        }
        return html.toString();
    }

    public static String getReadingChildQuesHtml(List<QuestionDto> questions) {
        StringBuffer html = new StringBuffer();
        if (CollectionUtils.isEmpty(questions)) {
            return "";
        }
        for (int i = 0; i < questions.size(); i++) {
            QuestionDto question = questions.get(i);
            html.append((i + 1)).append("、").append(question.getTitle()).append("<br/>");
            JSONArray options = (JSONArray) question.getOption();
            List<QuestionOptionDto> optionDtos = JSONObject.parseArray(question.getOption().toJSONString(), QuestionOptionDto.class);
            Integer optionNum = QuestionUtils.calculateOptionArrange(optionDtos);
            for (int j = 0; j < options.size(); j++) {
                JSONObject option = options.getJSONObject(j);
                String name = option.getString("name");
                String content = option.getString("content");
                html.append(name).append(".").append(content);
                // 一行四个选项
                if (optionNum == 4) {
                    html.append("&nbsp;&nbsp;&nbsp;");
                }
                // 一行俩个选项
                if (optionNum == 2) {
                    if (j % 2 == 0) {
                        html.append("&nbsp;&nbsp;&nbsp;");
                    } else {
                        html.append("<br/>");
                    }
                }
                // 一行一个选项
                if (optionNum == 1) {
                    html.append("<br/>");
                }
                if (j == options.size() - 1) {
                    html.append("<br/>");
                }
            }
            html.append("<br/>");
        }
        return html.toString();
    }

    /**
     * 获取完形填空html
     *
     * @param question
     * @param withAnswer
     * @param withAnalysis
     * @param withExamPoint
     * @return
     */
    public static String getClozeQuestionHtml(QuestionDto question, Boolean withTitle, Boolean withAnswer, Boolean withAnalysis, Boolean withExamPoint) {
        StringBuffer html = new StringBuffer();
//        html.append("(").append(getQuestionTypeChinese(question.getBasicQuestionType())).append(")");
        html.append(question.getQuestionNo());
        if (withTitle) {
            html.append(question.getTitle()).append("<br/>");
            //选项
//            if (question.getBasicQuestionType().equals(QuestionConstant.TYPE.COMB)) {
            JSONArray options = (JSONArray) question.getOption();
            if (null != options) {
                for (int i = 0; i < options.size(); i++) {
                    html.append((i + 1)).append(".&nbsp; ");
                    JSONObject option = options.getJSONObject(i);
                    JSONArray childs = option.getJSONArray("childs");
                    //判断选项排列
                    List<QuestionOptionDto> optionDtos = JSONObject.parseArray(option.getString("childs"), QuestionOptionDto.class);
                    Integer optionNum = QuestionUtils.calculateOptionArrange(optionDtos);
                    for (int j = 0; j < childs.size(); j++) {
                        JSONObject childOption = childs.getJSONObject(j);
                        html.append(childOption.getString("name")).append(".").append(childOption.getString("content"));
                        // 一行四个选项
                        if (optionNum == 4) {
                            html.append("&nbsp;&nbsp;&nbsp; ");
                        }
                        // 一行俩个选项
                        if (optionNum == 2) {
                            if (j % 2 == 0) {
                                html.append("&nbsp;&nbsp;&nbsp;");
                            } else {
                                html.append("<br/>");
                            }
                        }
                        // 一行一个选项
                        if (optionNum == 1) {
                            html.append("<br/>");
                        }

                    }
                    html.append("<br/>");
                }
            }
//            }
        }
        if (withAnswer) {
            html.append("答案：");
//            if (question.getType().equals(QuestionConstant.TYPE.COMB)) {
            JSONArray options = (JSONArray) question.getRightAnswer();
            if (null != options) {
                String rightAnswerContent = "";
                String rightAnswerString = "";
                int answerStartOrder = 1;
                for (int i = 0; i < options.size(); i++) {
                    JSONObject answer = options.getJSONObject(i);
                    String rightAnswer = answer.getString("content");
                    if ((i + 1) % 5 == 0) {
                        rightAnswerContent += answerStartOrder + "-" + (i + 1) + rightAnswerString + "&nbsp; &nbsp; ";

                        answerStartOrder = (i + 1);
                        rightAnswerString = "";
                    } else {
                        rightAnswerString += rightAnswer;
                    }
                }
                if (!StringUtils.isEmpty(rightAnswerContent)) {
                    html.append(rightAnswerContent).append("<br/>");
                }
            }
//            }
        }
        //解析
        if (withAnalysis) {
            html.append("解析：").append(question.getAnalysis() == null ? "" : question.getAnalysis()).append("<br/>");
        }
        //考点分析
        if (withExamPoint) {
            html.append("考点分析：").append(question.getExamPoint() == null ? "" : question.getExamPoint()).append("<br/>");
        }
        return html.toString();
    }

    /**
     * 获取综合题html
     *
     * @param question
     * @param withAnswer
     * @param withAnalysis
     * @param withExamPoint
     * @return
     */
    public static String getCombQuestionHtml(QuestionDto question, Boolean withTitle, Boolean withAnswer, Boolean withAnalysis, Boolean withExamPoint) {
        StringBuffer html = new StringBuffer();
//        html.append("(").append(getQuestionTypeChinese(question.getBasicQuestionType())).append(")");
        html.append(question.getQuestionNo());
        if (withTitle) {
            html.append(question.getTitle()).append("<br/>");
        }
        List<QuestionDto> questionChild = _questionService.getQuestionChild(question.getId());
        if (!CollectionUtils.isEmpty(questionChild)) {
            for (QuestionDto questionDto : questionChild) {
                String childQuesHtml = "";
                if (questionDto.getType().equals(QuestionTypeEnum.SINGLE.getValue())) {
                    childQuesHtml = getSingleOrMulQuestionHtml(questionDto, withTitle, withAnswer, withAnalysis, withExamPoint);
                } else if (questionDto.getType().equals(QuestionTypeEnum.BLANK.getValue())) {
                    childQuesHtml = getBlankQuestionHtml(questionDto, withTitle, withAnswer, withAnalysis, withExamPoint);
                } else if (questionDto.getType().equals(QuestionTypeEnum.JUDGE.getValue())) {
                    childQuesHtml = getJudgeQuestionHtml(questionDto, withTitle, withAnswer, withAnalysis, withExamPoint);
                } else if (questionDto.getType().equals(QuestionTypeEnum.ESSAY.getValue())) {
                    childQuesHtml = getEssayQuestionHtml(questionDto, withTitle, withAnswer, withAnalysis, withExamPoint);
                } else if (questionDto.getType().equals(QuestionTypeEnum.ORDER.getValue())) {
                    childQuesHtml = getOrderQuestionHtml(questionDto, withTitle, withAnswer, withAnalysis, withExamPoint);
                } else if (questionDto.getType().equals(QuestionTypeEnum.LINK.getValue())) {
                    childQuesHtml = getLinkQuestionHtml(questionDto, withTitle, withAnswer, withAnalysis, withExamPoint);
                } else if (questionDto.getType().equals(QuestionTypeEnum.MATCH.getValue())) {
                    childQuesHtml = getMatchQuestionHtml(questionDto, withTitle, withAnswer, withAnalysis, withExamPoint);
                } else if (questionDto.getType().equals(QuestionTypeEnum.READING.getValue())) {
                    childQuesHtml = getReadingQuestionHtml(questionDto, withTitle, withAnswer, withAnalysis, withExamPoint);
                } else if (questionDto.getType().equals(QuestionTypeEnum.CLOZE.getValue())) {
                    childQuesHtml = getClozeQuestionHtml(questionDto, withTitle, withAnswer, withAnalysis, withExamPoint);
                }
                html.append(childQuesHtml).append("<br/>");
            }
        }
        return html.toString();
    }

    public static void createQuestionTable(PaperWidthConstant paperWidthConstant, String rootPath, QuestionDto question, DocumentBuilder builder, Boolean withTitle, Boolean withAnswer, Boolean withAnalysis, Boolean withExamPoint) throws Exception {
        Integer questionType = _questionTypeRelationService.queryToolQuestionTypeByJyType(question.getSubjectId(), question.getType());
        if (withTitle) {
            String title = replaceImgPath(rootPath, question.getTitle().trim()).replaceAll("<ol>||</ol>","").replaceAll("<li","<p").replaceAll("</li>","</p>");
            // 题号列
            String questionNo = questionType != null && !questionType.equals(QuestionTypeEnum.READING.getValue()) && !questionType.equals(QuestionTypeEnum.CLOZE.getValue()) ? question.getOrderNo() + 1 + "." : "";
            OfficeUtils.createCellWriteContent(builder, paperWidthConstant.getINDEX_WIDTH(), ParagraphAlignment.CENTER, "", false);
            // 题干列
            OfficeUtils.createCellInsertHtml(builder, paperWidthConstant.getTITLE_WIDTH(), 0, questionNo + title, true);
        }
        if (questionType == null) {
            questionType = QuestionTypeEnum.OTHER.getValue();
        }
        question.setBasicQuestionType(questionType);
        if (questionType == 1 || questionType == 2) {
            question.setOrderNo(question.getOrderNo() + 1);
            createSingleQuestionTable(paperWidthConstant, rootPath, question, builder, withTitle, withAnswer, withAnalysis, withExamPoint);
            return;
        }
        if (questionType == 9) {
            createReadingQuestionTable(paperWidthConstant, rootPath, question, builder, withTitle, withAnswer, withAnalysis, withExamPoint);
            return;
        }
        if (questionType == 10) {
            createCloneQuestionTable(paperWidthConstant, rootPath, question, builder, withTitle, withAnswer, withAnalysis, withExamPoint);
            return;
        }
        // 其他题型
        question.setOrderNo(question.getOrderNo() + 1);
        if (withAnswer) {
            JSONArray answers = (JSONArray) question.getRightAnswer();
            String answer = "";
            if (answers != null && answers.size() == 1) {
                answer = answers.getJSONObject(0).getString("content");
            }
            // 填空题多个答案
            if (answers != null && answers.size() > 1) {
                for (int i = 0; i < answers.size(); i++) {
                    JSONObject json = answers.getJSONObject(i);
                    answer += "("+(i+1)+")" + json.getString("content") + "&nbsp;&nbsp;&nbsp;&nbsp;";
                    if (i < answers.size() - 1) {
                        answer += "<br>";
                    }
                }
            }

            String index = withTitle ? "" : question.getOrderNo() + ".";
            OfficeUtils.createCellWriteContent(builder, paperWidthConstant.getINDEX_WIDTH(), ParagraphAlignment.CENTER, "", false);
            OfficeUtils.createCellInsertHtml(builder, paperWidthConstant.getTITLE_WIDTH(), 0, index + "【答案】" + answer, true);
        }
        if (withAnalysis) {
            OfficeUtils.createCellInsertHtml(builder, paperWidthConstant.getINDEX_WIDTH(), 0, "", false);
            OfficeUtils.createCellInsertHtml(builder, paperWidthConstant.getTITLE_WIDTH(), 0, "【解析】" + (question.getAnalysis() == null ? "" : question.getAnalysis()), true);
        }
        if(questionType.equals(QuestionTypeEnum.ESSAY.getValue()) || questionType.equals(QuestionTypeEnum.OTHER.getValue())){
            OfficeUtils.createBlankRow(builder, paperWidthConstant.getTOTAL_WIDTH(),300,true);
        }
    }

    public static void createSingleQuestionTable(PaperWidthConstant paperWidthConstant, String rootPath, QuestionDto question, DocumentBuilder builder, Boolean withTitle, Boolean withAnswer, Boolean withAnalysis, Boolean withExamPoint) throws Exception {
        JSONArray options = (JSONArray) question.getOption();
        if (null == options) {
            return;
        }
        if (withTitle) {
            List<QuestionOptionDto> optionDtos = JSONObject.parseArray(question.getOption().toJSONString(), QuestionOptionDto.class);
            Integer optionNum = QuestionUtils.calculateOptionArrange(optionDtos);
            for (int k = 0; k < optionDtos.size(); k++) {
                QuestionOptionDto questionOptionDto = optionDtos.get(k);
                int index = questionOptionDto.getNo();
                String name = QuestionConstant.OPTION_ORDER.substring(index - 1, index);
                String content = name + "." + replaceImgPath(rootPath, questionOptionDto.getContent());
                if (optionNum == 1) {
                    // 题号列
                    OfficeUtils.createCellInsertHtml(builder, paperWidthConstant.getINDEX_WIDTH(), 0, "", false);
                    // 题干列
                    OfficeUtils.createCellInsertHtml(builder, paperWidthConstant.getONE_OPTION_WIDTH(), 0, content, true);
                } else if (optionNum == 2) {
                    if (k % 2 == 0) {
                        // 题号列
                        OfficeUtils.createCellInsertHtml(builder, paperWidthConstant.getINDEX_WIDTH(), 0, "", false);
                    }
                    boolean endRow = false;
                    if ((k != 0 && k % 2 == 1) || k == options.size() - 1) {
                        endRow = true;
                    }
                    // 题干列
                    OfficeUtils.createCellInsertHtml(builder, paperWidthConstant.getTWO_OPTION_WIDTH(), 0, content, endRow);
                } else {
                    if (k == 0) {
                        // 题号列
                        OfficeUtils.createCellInsertHtml(builder, paperWidthConstant.getINDEX_WIDTH(), 0, "", false);
                    }
                    boolean endRow = false;
                    if ((k != 0 && k % 3 == 0) || k == options.size() - 1) {
                        endRow = true;
                    }
                    // 题干列
                    OfficeUtils.createCellInsertHtml(builder, paperWidthConstant.getFOUR_OPTION_WIDTH(), 0, content, endRow);

                }
            }
        }
        if (withAnswer) {
            JSONArray answers = (JSONArray) question.getRightAnswer();
            String answer = "";
            if (answers != null && answers.size() > 0) {
                answer = answers.getJSONObject(0).getString("content");
            }
            String index = withTitle ? "" : question.getOrderNo() + ".";
            OfficeUtils.createCellWriteContent(builder, paperWidthConstant.getINDEX_WIDTH(), ParagraphAlignment.CENTER, index, false);
            OfficeUtils.createCellInsertHtml(builder, paperWidthConstant.getTITLE_WIDTH(), 0, "【答案】" + replaceImgPath(rootPath, answer), true);
        }
        if (withAnalysis) {
            OfficeUtils.createCellInsertHtml(builder, paperWidthConstant.getINDEX_WIDTH(), 0, "", false);
            OfficeUtils.createCellInsertHtml(builder, paperWidthConstant.getTITLE_WIDTH(), 0, "【解析】" + replaceImgPath(rootPath, question.getAnalysis()), true);
        }
    }

    public static void createCloneQuestionTable(PaperWidthConstant paperWidthConstant,String rootPath, QuestionDto question, DocumentBuilder builder, Boolean withTitle, Boolean withAnswer, Boolean withAnalysis, Boolean withExamPoint) throws Exception {
        JSONArray options = (JSONArray) question.getOption();
        List<Integer> indexs = new ArrayList<>();
        if (withTitle && null != options) {
            for (int i = 0; i < options.size(); i++) {
                indexs.add(question.getOrderNo() + 1);
                question.setOrderNo(question.getOrderNo() + 1);
                // 题号列
                OfficeUtils.createCellInsertHtml(builder, paperWidthConstant.getINDEX_WIDTH(), 0, "", false);
                JSONObject option = options.getJSONObject(i);
                JSONArray childs = option.getJSONArray("childs");
                //判断选项排列
                List<QuestionOptionDto> optionDtos = JSONObject.parseArray(option.getString("childs"), QuestionOptionDto.class);
                Integer optionNum = QuestionUtils.calculateOptionArrange(optionDtos);
                for (int k = 0; k < childs.size(); k++) {
                    if (k == 0) {
                        // 题号列
                        OfficeUtils.createCellInsertHtml(builder, paperWidthConstant.getCLONE_INDEX_WIDTH(), 0, question.getOrderNo() + ".", false);
                    }
                    JSONObject childOption = childs.getJSONObject(k);
                    int index = childOption.getInteger("no");
                    String name = QuestionConstant.OPTION_ORDER.substring(index - 1, index);
                    String content = name + "." + replaceImgPath(rootPath, childOption.getString("content"));
                    if (optionNum == 1) {
                        // 题号列
                        if (k != 0) {
                            OfficeUtils.createCellInsertHtml(builder, paperWidthConstant.getCLONE_INDEX_WIDTH(), 0, "", false);
                        }
                        // 一行一个选项，选项内容
                        OfficeUtils.createCellInsertHtml(builder, paperWidthConstant.getCLONE_ONE_OPTION_WIDTH(), 0, content, false);
                    } else if (optionNum == 2) {
                        if (k != 0 && k % 2 == 0) {
                            // 题号列
                            OfficeUtils.createCellInsertHtml(builder, paperWidthConstant.getCLONE_INDEX_WIDTH(), 0, "", false);
                        }
                        boolean endRow = false;
                        if ((k != 0 && k % 2 == 1) || k == options.size() - 1) {
                            endRow = true;
                        }
                        // 题干列
                        OfficeUtils.createCellInsertHtml(builder, paperWidthConstant.getCLONE_TWO_OPTION_WIDTH(), 0, content, endRow);

                    } else {
                        boolean endRow = false;
                        if ((k != 0 && k % 3 == 0) || k == options.size() - 1) {
                            endRow = true;
                        }
                        // 题干列
                        OfficeUtils.createCellInsertHtml(builder, paperWidthConstant.getCLONE_FOUR_OPTION_WIDTH(), 0, content, endRow);
                    }
                }
            }
        }
        // 教师版
        if (withTitle && withAnswer) {
            JSONArray answers = (JSONArray) question.getRightAnswer();
            String answer = "";
            if (answers != null && answers.size() > 0) {
                for (int i = 0; i < answers.size(); i++) {
                    JSONObject json = answers.getJSONObject(i);
                    answer += indexs.get(i) + "." + json.getString("content") + "&nbsp;&nbsp;";
                }
            }
            OfficeUtils.createCellInsertHtml(builder, paperWidthConstant.getINDEX_WIDTH(), 0, "", false);
            OfficeUtils.createCellInsertHtml(builder, paperWidthConstant.getTITLE_WIDTH(), 0, "【答案】" + replaceImgPath(rootPath, answer), true);
        }
        // 解析版
        if (!withTitle && withAnswer) {
            for (int i = 0; i < options.size(); i++) {
                indexs.add(question.getOrderNo() + 1);
                question.setOrderNo(question.getOrderNo() + 1);
            }
            JSONArray answers = (JSONArray) question.getRightAnswer();
            if (answers != null && answers.size() > 0) {
                for (int i = 0; i < answers.size(); i++) {
                    JSONObject answer = answers.getJSONObject(i);
                    OfficeUtils.createCellWriteContent(builder, paperWidthConstant.getINDEX_WIDTH(), ParagraphAlignment.CENTER, "", false);
                    OfficeUtils.createCellInsertHtml(builder, paperWidthConstant.getTITLE_WIDTH(), 0, indexs.get(i) + "." + "【答案】" + replaceImgPath(rootPath, answer.getString("content")), true);
                }
            }
        }
        if (withAnalysis) {
            OfficeUtils.createCellInsertHtml(builder, paperWidthConstant.getINDEX_WIDTH(), 0, "", false);
            OfficeUtils.createCellInsertHtml(builder, paperWidthConstant.getTITLE_WIDTH(), 0, "【解析】" + replaceImgPath(rootPath, question.getAnalysis()), true);
        }
    }

    public static void createReadingQuestionTable(PaperWidthConstant paperWidthConstant,String rootPath, QuestionDto question, DocumentBuilder builder, Boolean withTitle, Boolean withAnswer, Boolean withAnalysis, Boolean withExamPoint) throws Exception {
        //选项
        List<QuestionDto> childQuestion = _questionService.getQuestionChild(question.getId());
        List<Integer> indexs = new ArrayList<>();
        if (withTitle) {
            for (int i = 0; i < childQuestion.size(); i++) {
                indexs.add(question.getOrderNo() + 1);
                question.setOrderNo(question.getOrderNo() + 1);
                QuestionDto questionDto = childQuestion.get(i);
                if (question.getTitle().trim().startsWith("<p>")) {
                    question.setTitle(question.getTitle().trim().replaceFirst("<p>", "").replaceFirst("</p>", ""));
                }
                // 题号列
                OfficeUtils.createCellInsertHtml(builder, paperWidthConstant.getINDEX_WIDTH(), 0, "", false);
                // 题干列
                OfficeUtils.createCellInsertHtml(builder, paperWidthConstant.getONE_OPTION_WIDTH(), 0, question.getOrderNo() + "." + replaceImgPath(rootPath, questionDto.getTitle().trim()), true);

                JSONArray options = (JSONArray) questionDto.getOption();
                if (null == options) {
                    continue;
                }
                List<QuestionOptionDto> optionDtos = JSONObject.parseArray(questionDto.getOption().toJSONString(), QuestionOptionDto.class);
                Integer optionNum = QuestionUtils.calculateOptionArrange(optionDtos);
                for (int k = 0; k < optionDtos.size(); k++) {
                    QuestionOptionDto questionOptionDto = optionDtos.get(k);
                    int index = questionOptionDto.getNo();
                    String name = QuestionConstant.OPTION_ORDER.substring(index - 1, index);
                    String content = name + "." + replaceImgPath(rootPath, questionOptionDto.getContent());
                    if (optionNum == 1) {
//                        // 题号列
                        OfficeUtils.createCellInsertHtml(builder, paperWidthConstant.getINDEX_WIDTH(), 0, "", false);
                        // 题干列
                        OfficeUtils.createCellInsertHtml(builder, paperWidthConstant.getONE_OPTION_WIDTH(), 0, content, true);
                    } else if (optionNum == 2) {
                        if (k % 2 == 0) {
                            // 题号列
                            OfficeUtils.createCellInsertHtml(builder, paperWidthConstant.getINDEX_WIDTH(), 0, "", false);
                        }
                        boolean endRow = false;
                        if ((k != 0 && k % 2 == 1) || k == options.size() - 1) {
                            endRow = true;
                        }
                        // 题干列
                        OfficeUtils.createCellInsertHtml(builder, paperWidthConstant.getTWO_OPTION_WIDTH(), 0, content, endRow);
                    } else {
                        if (k == 0) {
                            // 题号列
                            OfficeUtils.createCellInsertHtml(builder, paperWidthConstant.getINDEX_WIDTH(), 0, "", false);
                        }
                        boolean endRow = false;
                        if ((k != 0 && k % 3 == 0) || k == options.size() - 1) {
                            endRow = true;
                        }
                        // 题干列
                        OfficeUtils.createCellInsertHtml(builder, paperWidthConstant.getFOUR_OPTION_WIDTH(), 0, content, endRow);
                    }
                }
            }
        }
        // 教师版
        if (withTitle && withAnswer) {
            JSONArray answers = (JSONArray) question.getRightAnswer();
            String answer = "";
            if (answers != null && answers.size() > 0) {
                for (int i = 0; i < answers.size(); i++) {
                    JSONObject json = answers.getJSONObject(i);
                    answer += indexs.get(i) + "." + json.getString("content") + "&nbsp;&nbsp;";
                }
            }
            OfficeUtils.createCellWriteContent(builder, paperWidthConstant.getINDEX_WIDTH(), ParagraphAlignment.CENTER, "", false);
            OfficeUtils.createCellInsertHtml(builder, paperWidthConstant.getTITLE_WIDTH(), 0, "【答案】" + replaceImgPath(rootPath, answer), true);
        }
        // 解析版
        if (!withTitle && withAnswer) {
            for (int i = 0; i < childQuestion.size(); i++) {
                indexs.add(question.getOrderNo() + 1);
                question.setOrderNo(question.getOrderNo() + 1);
            }
            JSONArray answers = (JSONArray) question.getRightAnswer();
            if (answers != null && answers.size() > 0) {
                for (int i = 0; i < answers.size(); i++) {
                    JSONObject answer = answers.getJSONObject(i);
                    OfficeUtils.createCellWriteContent(builder, paperWidthConstant.getINDEX_WIDTH(), ParagraphAlignment.CENTER, "", false);
                    OfficeUtils.createCellInsertHtml(builder, paperWidthConstant.getTITLE_WIDTH(), 0, indexs.get(i) + "." + "【答案】" + replaceImgPath(rootPath, answer.getString("content")), true);
                }
            }
        }
        if (withAnalysis) {
            OfficeUtils.createCellInsertHtml(builder, paperWidthConstant.getINDEX_WIDTH(), 0, "", false);
            OfficeUtils.createCellInsertHtml(builder, paperWidthConstant.getTITLE_WIDTH(), 0, "【解析】" + replaceImgPath(rootPath, question.getAnalysis()), true);
        }
    }

    public static void formatQuestion(QuestionDto question) {
        // 目前只处理完形填空和阅读理解
        if (question.getBasicQuestionType() == null || !question.getBasicQuestionType().equals(QuestionTypeEnum.CLOZE.getValue()) && !question.getBasicQuestionType().equals(QuestionTypeEnum.READING.getValue())) {
            return;
        }

        // 处理题干中的图片
        String title = question.getTitle();

        String blankStr = "";
        if (question.getBasicQuestionType() != null && question.getBasicQuestionType().equals(QuestionTypeEnum.CLOZE.getValue())) {
            if (StringUtils.isNotEmpty(title)) {
                title = title.replace("<br>", "<br>" + blankStr).replace("<br/>", "<br>" + blankStr);
                if (title.startsWith("&nbsp;")) {
                    title = title.replaceFirst("[&nbsp;]+", blankStr);
                } else {
                    title = blankStr + title;
                }
                int index = question.getOrderNo();
                String replaceStr = "__<u>##</u>__";
                title = title.replaceAll(com.xh.tools.question.constant.QuestionConstant.REGEX_MATCH_RULE.CLOZE_BLANK_SELECT, replaceStr);
                Matcher childMatcher = RegexUtils.getMatcher(title, replaceStr);
                while (childMatcher.find()) {
                    String blank = childMatcher.group();
                    String newBlank = blank.replaceAll("##", String.valueOf(++index));
                    title = title.replaceFirst(blank, newBlank);
                }
                question.setTitle(title);
            }
        } else if (question.getBasicQuestionType() != null && question.getBasicQuestionType().equals(QuestionTypeEnum.READING.getValue())) {
            if (StringUtils.isNotEmpty(title)) {
                if (title.startsWith("&nbsp;")) {
                    title = title.replaceFirst("[&nbsp;]+", blankStr);
                } else {
                    title = blankStr + title;
                }
                title = title.replace("<br>", "<br>" + blankStr).replace("<br/>", "<br>" + blankStr);
                question.setTitle(title);
            }
        }
    }

    public static String replaceImgPath(String rootPath, String html) {
        if (StringUtils.isEmpty(html)) {
            return "";
        }else{
            html = html.replaceAll("<p style=\"margin-top:0pt; margin-bottom:0pt; text-align:center; line-height:125%; widows:0; orphans:0; font-size:14pt\"><b>&nbsp;</b></p><br/>","");
            return html.replaceAll("src=\"/test/upload/ueditor/image", "src=\"" + rootPath + "test/upload/ueditor/image");
        }
//        Document doc = Jsoup.parse(html);
//        Integer length = 0;
//        for (Element element : doc.getElementsByTag("img")) {
//            String src = element.attr("src");
//            if (!src.startsWith("data:image/png;base64,")) {
//                element.attr("src", rootPath + src);
//            }
//        }
    }
}
